zyjj-web-sdk 1.1.34 → 2.0.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/lib/api/api.d.ts +2 -1
- package/lib/api/entity.d.ts +2 -2
- package/lib/contract-v2/client.d.ts +8 -0
- package/lib/contract-v2/fixtures.d.ts +17 -0
- package/lib/contract-v2/index.d.ts +8 -0
- package/lib/contract-v2/index.js +314 -0
- package/lib/contract-v2/manifest.d.ts +15 -0
- package/lib/contract-v2/matrix.d.ts +8 -0
- package/lib/contract-v2/remote-product.d.ts +2 -0
- package/lib/contract-v2/schema.d.ts +13 -0
- package/lib/contract-v2/task-ledger.d.ts +16 -0
- package/lib/contract-v2/types.d.ts +375 -0
- package/lib/index.d.ts +9 -124
- package/lib/index.js +67162 -3677
- package/lib/index.umd.cjs +363 -20
- package/lib/tool/utils.d.ts +1 -1
- package/lib/types/cloud.d.ts +7 -1
- package/lib/types/resource.d.ts +24 -0
- package/lib/types/tool-task.d.ts +3 -3
- package/package.json +14 -4
- package/lib/tool/db.d.ts +0 -7
- package/lib/types/local-task.d.ts +0 -168
- package/lib/types/new-local-task.d.ts +0 -68
package/lib/api/api.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AddTaskReq, GetCosResp, GetPageInfo, MqttClientInfo, UserLoginReq, GetPageReq, GetToolDetailResp, SendCommonRequestInfo } from './entity.ts';
|
|
2
2
|
import { AppInfo, TaskInfo, ToolInfo, UserInfo } from "../types/cloud.ts";
|
|
3
|
+
export declare const base: string;
|
|
3
4
|
export declare const UserLogin: (data: UserLoginReq) => Promise<string>;
|
|
4
5
|
export declare const GetAppInfo: (os: string, version: string, uid?: string) => Promise<AppInfo>;
|
|
5
6
|
export declare const UserRegister: (data: UserLoginReq) => Promise<void>;
|
|
@@ -22,7 +23,7 @@ export declare const ToolInc: (id: string) => Promise<unknown>;
|
|
|
22
23
|
export declare const GetToolTagList: () => Promise<string[]>;
|
|
23
24
|
export declare const GetTencentCosInfo: () => Promise<GetCosResp>;
|
|
24
25
|
export declare const GetAliynOssInfo: () => Promise<GetCosResp>;
|
|
25
|
-
export declare const AddTask: (data: AddTaskReq) => Promise<string
|
|
26
|
+
export declare const AddTask: (data: AddTaskReq) => Promise<string | Record<string, unknown>>;
|
|
26
27
|
export declare const GetTaskInfo: (id: string) => Promise<TaskInfo>;
|
|
27
28
|
export declare const GetMqttTaskClientInfo: () => Promise<MqttClientInfo>;
|
|
28
29
|
export declare const GetMaterialTagList: () => Promise<string[]>;
|
package/lib/api/entity.d.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type HostCapability, type HostClientV2, type HostEvent, type HostRequest, type HostResponse } from './types.ts';
|
|
2
|
+
export interface HostTransportV2 {
|
|
3
|
+
invoke<C extends HostCapability>(request: HostRequest<C>): Promise<HostResponse<C>>;
|
|
4
|
+
subscribe(listener: (event: HostEvent) => void): () => void;
|
|
5
|
+
cancel(requestId: string): Promise<void>;
|
|
6
|
+
dispose?(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createHostClientV2(transport: HostTransportV2): HostClientV2;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HostRequest, type RemoteManifestV2 } from './types.ts';
|
|
2
|
+
export declare const validRuntimeInfoRequest: HostRequest;
|
|
3
|
+
export declare const invalidTraversalRequest: {
|
|
4
|
+
requestId: string;
|
|
5
|
+
contractVersion: "2.0.0";
|
|
6
|
+
capability: string;
|
|
7
|
+
payload: {
|
|
8
|
+
resource: {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
mime: string;
|
|
12
|
+
size: number;
|
|
13
|
+
uri: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const remoteManifestFixture: RemoteManifestV2;
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
var L = Object.defineProperty;
|
|
2
|
+
var $ = (e, t, s) => t in e ? L(e, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : e[t] = s;
|
|
3
|
+
var E = (e, t, s) => $(e, typeof t != "symbol" ? t + "" : t, s);
|
|
4
|
+
const m = "2.0.0", N = ["system.getRuntimeInfo", "navigation.openExternal", "navigation.close", "navigation.reveal", "files.pick", "files.read", "files.write", "files.stat", "files.removeTemp", "ffmpeg.execute", "ffmpeg.probe", "ffmpeg.cancel", "downloads.start", "downloads.cancel", "tasks.create", "tasks.appendEvent", "tasks.snapshot", "tasks.list", "tasks.cancel", "tasks.clear", "cloud.upload", "cloud.download", "cloud.executeTask", "transport.subscribeTask", "transport.unsubscribeTask", "settings.get", "settings.set"], _ = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]), c = (e) => typeof e == "object" && e !== null && !Array.isArray(e), i = (e, t = 1024) => typeof e == "string" && e.length > 0 && e.length <= t, p = (e, t = 0, s = Number.MAX_SAFE_INTEGER) => typeof e == "number" && Number.isInteger(e) && e >= t && e <= s, u = (e, t = 0, s = Number.MAX_SAFE_INTEGER) => typeof e == "number" && Number.isFinite(e) && e >= t && e <= s, o = (e, t) => Object.keys(e).every((s) => t.includes(s)) && t.every((s) => Object.prototype.hasOwnProperty.call(e, s)), j = (e, t, s = []) => Object.keys(e).every((d) => [...t, ...s].includes(d)) && t.every((d) => Object.prototype.hasOwnProperty.call(e, d)), w = (e) => i(e, 4096) && (() => {
|
|
5
|
+
try {
|
|
6
|
+
const t = new URL(e);
|
|
7
|
+
return t.protocol === "https:" || t.protocol === "http:";
|
|
8
|
+
} catch {
|
|
9
|
+
return !1;
|
|
10
|
+
}
|
|
11
|
+
})(), S = (e, t = 0) => t <= 8 && (e === null || typeof e == "boolean" || typeof e == "string" && e.length <= 16 * 1024 || typeof e == "number" && Number.isFinite(e) || Array.isArray(e) && e.length <= 256 && e.every((s) => S(s, t + 1)) || c(e) && Object.keys(e).length <= 256 && Object.values(e).every((s) => S(s, t + 1))), z = (e, t) => S(e) && new TextEncoder().encode(JSON.stringify(e)).byteLength <= t;
|
|
12
|
+
function I(e) {
|
|
13
|
+
return c(e) && o(e, ["id", "name", "mime", "size"]) && i(e.id, 128) && i(e.name, 512) && i(e.mime, 128) && p(e.size, 0, 1024 * 1024 * 1024 * 16);
|
|
14
|
+
}
|
|
15
|
+
function T(e) {
|
|
16
|
+
return c(e) && o(e, ["eventId", "taskId", "seq", "at", "type", "data"]) && i(e.eventId, 128) && i(e.taskId, 128) && p(e.seq, 1) && i(e.at, 64) && !Number.isNaN(Date.parse(e.at)) && ["queued", "running", "stage.started", "stage.progress", "stage.retry", "log", "completed", "failed", "cancelled"].includes(String(e.type)) && c(e.data) && Object.keys(e.data).length <= 64 && Object.values(e.data).every((t) => t === null || ["string", "number", "boolean"].includes(typeof t));
|
|
17
|
+
}
|
|
18
|
+
function D(e) {
|
|
19
|
+
return c(e) && o(e, []);
|
|
20
|
+
}
|
|
21
|
+
const h = (e) => i(e, 128) && /^[A-Za-z0-9_-]+$/.test(e), C = (e) => typeof e == "string" && (e === "transparent" || /^#[0-9A-Fa-f]{6}$/.test(e)), M = (e) => {
|
|
22
|
+
for (let t = 0; t < e.length; t += 1) {
|
|
23
|
+
const s = e.charCodeAt(t);
|
|
24
|
+
if (s <= 31 || s === 127) return !0;
|
|
25
|
+
}
|
|
26
|
+
return !1;
|
|
27
|
+
}, k = (e) => p(e, 16, 4096) && e % 2 === 0, F = (e) => c(e) && o(e, ["startSeconds", "durationSeconds"]) && u(e.startSeconds, 0, 86400) && u(e.durationSeconds, 1e-3, 86400) && e.startSeconds + e.durationSeconds <= 86400, O = (e) => c(e) && o(e, ["sourceId", "resource", "mediaKind"]) && h(e.sourceId) && I(e.resource) && ["video", "audio", "image"].includes(String(e.mediaKind)), R = (e) => !(!c(e) || !j(e, ["name", "mime"], ["width", "height", "fps", "videoCodec", "audioCodec", "preset", "crf"]) || !i(e.name, 256) || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/.test(e.name) || !["video/mp4", "video/webm", "audio/mpeg", "audio/mp4", "image/png"].includes(String(e.mime)) || !{
|
|
28
|
+
"video/mp4": /\.mp4$/i,
|
|
29
|
+
"video/webm": /\.webm$/i,
|
|
30
|
+
"audio/mpeg": /\.mp3$/i,
|
|
31
|
+
"audio/mp4": /\.(?:m4a|mp4)$/i,
|
|
32
|
+
"image/png": /\.png$/i
|
|
33
|
+
}[String(e.mime)].test(e.name) || e.width !== void 0 && !k(e.width) || e.height !== void 0 && !k(e.height) || e.width === void 0 != (e.height === void 0) || e.fps !== void 0 && !p(e.fps, 1, 60) || e.videoCodec !== void 0 && !["copy", "libx264", "libvpx-vp9"].includes(String(e.videoCodec)) || e.audioCodec !== void 0 && !["copy", "aac", "libopus", "libmp3lame"].includes(String(e.audioCodec)) || e.preset !== void 0 && !["ultrafast", "veryfast", "fast", "medium", "slow"].includes(String(e.preset)) || e.crf !== void 0 && !p(e.crf, 0, 51) || e.mime === "video/mp4" && e.videoCodec !== void 0 && !["copy", "libx264"].includes(String(e.videoCodec)) || e.mime === "video/webm" && e.videoCodec !== void 0 && !["copy", "libvpx-vp9"].includes(String(e.videoCodec)) || e.mime === "audio/mpeg" && e.audioCodec !== "libmp3lame" || e.mime === "audio/mp4" && e.audioCodec !== "aac"), H = (e) => c(e) && o(e, ["x", "y", "width", "height", "rotation", "opacity"]) && p(e.x, -4096, 4096) && p(e.y, -4096, 4096) && k(e.width) && k(e.height) && u(e.rotation, -360, 360) && u(e.opacity, 0, 1);
|
|
34
|
+
function U(e) {
|
|
35
|
+
if (!c(e) || !["transcode", "composition", "frame-sequence"].includes(String(e.kind))) return !1;
|
|
36
|
+
if (e.kind === "transcode") {
|
|
37
|
+
if (!j(e, ["kind", "source", "includeVideo", "includeAudio", "output"], ["trim", "loop"]) || !O(e.source) || typeof e.includeVideo != "boolean" || typeof e.includeAudio != "boolean" || !e.includeVideo && !e.includeAudio || !R(e.output) || e.trim !== void 0 && !F(e.trim) || e.loop !== void 0 && typeof e.loop != "boolean") return !1;
|
|
38
|
+
const n = e.source, a = e.output;
|
|
39
|
+
return e.loop === !0 && n.mediaKind !== "image" || e.includeVideo && n.mediaKind === "audio" || !e.includeVideo && (a.videoCodec !== void 0 || a.width !== void 0 || a.fps !== void 0) || !e.includeAudio && a.audioCodec !== void 0 ? !1 : !(a.videoCodec === "copy" && (a.width !== void 0 || a.fps !== void 0));
|
|
40
|
+
}
|
|
41
|
+
if (e.kind === "frame-sequence") {
|
|
42
|
+
if (!o(e, ["kind", "width", "height", "fps", "frames", "output"]) || !k(e.width) || !k(e.height) || !p(e.fps, 1, 60) || !Array.isArray(e.frames) || e.frames.length < 2 || e.frames.length > 36e3 || !R(e.output)) return !1;
|
|
43
|
+
const n = e.output;
|
|
44
|
+
if (!["video/mp4", "video/webm"].includes(String(n.mime)) || n.width !== e.width || n.height !== e.height || n.fps !== e.fps || !["libx264", "libvpx-vp9"].includes(String(n.videoCodec)) || n.audioCodec !== void 0) return !1;
|
|
45
|
+
const a = /* @__PURE__ */ new Set();
|
|
46
|
+
let y = 0;
|
|
47
|
+
for (const f of e.frames) {
|
|
48
|
+
if (!c(f) || !o(f, ["frameId", "resource"]) || !h(f.frameId) || a.has(f.frameId) || !I(f.resource) || f.resource.mime !== "image/png") return !1;
|
|
49
|
+
a.add(f.frameId), y += f.resource.size;
|
|
50
|
+
}
|
|
51
|
+
return y <= 512 * 1024 * 1024 && e.width * e.height * e.frames.length <= 4e9;
|
|
52
|
+
}
|
|
53
|
+
if (!o(e, ["kind", "canvas", "sources", "videoTracks", "audioTracks", "textLayers", "output"]) || !c(e.canvas) || !o(e.canvas, ["width", "height", "fps", "durationSeconds", "background"]) || !k(e.canvas.width) || !k(e.canvas.height) || !p(e.canvas.fps, 1, 60) || !u(e.canvas.durationSeconds, 0.04, 3600) || !C(e.canvas.background) || !Array.isArray(e.sources) || e.sources.length > 64 || !Array.isArray(e.videoTracks) || e.videoTracks.length > 32 || !Array.isArray(e.audioTracks) || e.audioTracks.length > 32 || !Array.isArray(e.textLayers) || e.textLayers.length > 64 || !R(e.output)) return !1;
|
|
54
|
+
const t = e.output;
|
|
55
|
+
if (!["video/mp4", "video/webm"].includes(String(t.mime)) || t.width !== e.canvas.width || t.height !== e.canvas.height || t.fps !== e.canvas.fps || !["libx264", "libvpx-vp9"].includes(String(t.videoCodec))) return !1;
|
|
56
|
+
const s = /* @__PURE__ */ new Map();
|
|
57
|
+
let d = 0;
|
|
58
|
+
for (const n of e.sources) {
|
|
59
|
+
if (!O(n)) return !1;
|
|
60
|
+
const a = n;
|
|
61
|
+
if (s.has(a.sourceId)) return !1;
|
|
62
|
+
s.set(a.sourceId, a), d += a.resource.size;
|
|
63
|
+
}
|
|
64
|
+
if (d > 2 * 1024 * 1024 * 1024) return !1;
|
|
65
|
+
const r = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Set(), g = /* @__PURE__ */ new Set();
|
|
66
|
+
let b = 0;
|
|
67
|
+
for (const n of e.videoTracks) {
|
|
68
|
+
if (!c(n) || !o(n, ["trackId", "mode", "layer", "clips"]) || !h(n.trackId) || r.has(n.trackId) || !["concat", "overlay"].includes(String(n.mode)) || !p(n.layer, 0, 127) || g.has(n.layer) || !Array.isArray(n.clips) || !n.clips.length || n.clips.length > 128) return !1;
|
|
69
|
+
r.add(n.trackId), g.add(n.layer);
|
|
70
|
+
let a = null, y = null;
|
|
71
|
+
for (const f of n.clips) {
|
|
72
|
+
if (!c(f) || !o(f, ["clipId", "sourceId", "timelineStartSeconds", "sourceStartSeconds", "durationSeconds", "transform"]) || !h(f.clipId) || l.has(f.clipId) || !h(f.sourceId) || !u(f.timelineStartSeconds, 0, 3600) || !u(f.sourceStartSeconds, 0, 86400) || !u(f.durationSeconds, 0.04, 3600) || f.timelineStartSeconds + f.durationSeconds > e.canvas.durationSeconds + 1e-3 || !H(f.transform)) return !1;
|
|
73
|
+
const x = s.get(f.sourceId);
|
|
74
|
+
if (!x || !["video", "image"].includes(String(x.mediaKind)) || x.mediaKind === "image" && f.sourceStartSeconds !== 0 || n.mode === "concat" && a !== null && Math.abs(f.timelineStartSeconds - a) > 1e-3) return !1;
|
|
75
|
+
const A = f.transform, V = `${A.x}:${A.y}:${A.width}:${A.height}`;
|
|
76
|
+
if (n.mode === "concat" && y !== null && V !== y) return !1;
|
|
77
|
+
n.mode === "concat" && (y = V), a = f.timelineStartSeconds + f.durationSeconds, l.add(f.clipId), b += 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const n of e.audioTracks) {
|
|
81
|
+
if (!c(n) || !o(n, ["trackId", "clips"]) || !h(n.trackId) || r.has(n.trackId) || !Array.isArray(n.clips) || !n.clips.length || n.clips.length > 128) return !1;
|
|
82
|
+
r.add(n.trackId);
|
|
83
|
+
for (const a of n.clips) {
|
|
84
|
+
if (!c(a) || !o(a, ["clipId", "sourceId", "timelineStartSeconds", "sourceStartSeconds", "durationSeconds", "volume"]) || !h(a.clipId) || l.has(a.clipId) || !h(a.sourceId) || !u(a.timelineStartSeconds, 0, 3600) || !u(a.sourceStartSeconds, 0, 86400) || !u(a.durationSeconds, 0.04, 3600) || a.timelineStartSeconds + a.durationSeconds > e.canvas.durationSeconds + 1e-3 || !u(a.volume, 0, 4)) return !1;
|
|
85
|
+
const y = s.get(a.sourceId);
|
|
86
|
+
if (!y || !["video", "audio"].includes(String(y.mediaKind))) return !1;
|
|
87
|
+
l.add(a.clipId), b += 1;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const n of e.textLayers) {
|
|
91
|
+
if (!c(n) || !o(n, ["layerId", "text", "timelineStartSeconds", "durationSeconds", "x", "y", "fontSize", "color", "background", "opacity", "layer"]) || !h(n.layerId) || l.has(n.layerId) || !i(n.text, 512) || M(n.text) || !u(n.timelineStartSeconds, 0, 3600) || !u(n.durationSeconds, 0.04, 3600) || n.timelineStartSeconds + n.durationSeconds > e.canvas.durationSeconds + 1e-3 || !p(n.x, -4096, 4096) || !p(n.y, -4096, 4096) || !p(n.fontSize, 8, 400) || !C(n.color) || !C(n.background) || !u(n.opacity, 0, 1) || !p(n.layer, 0, 127) || g.has(n.layer)) return !1;
|
|
92
|
+
g.add(n.layer), l.add(n.layerId);
|
|
93
|
+
}
|
|
94
|
+
return e.audioTracks.length && !["aac", "libopus"].includes(String(t.audioCodec)) || !e.audioTracks.length && t.audioCodec !== void 0 ? !1 : b <= 256 && b + e.textLayers.length > 0;
|
|
95
|
+
}
|
|
96
|
+
function B(e, t) {
|
|
97
|
+
return c(t) ? ["system.getRuntimeInfo", "navigation.close", "tasks.list", "tasks.clear"].includes(e) ? D(t) : e === "navigation.openExternal" ? o(t, ["url"]) && w(t.url) : e === "navigation.reveal" || e === "files.read" || e === "files.stat" || e === "files.removeTemp" || e === "ffmpeg.probe" ? o(t, ["resource"]) && I(t.resource) : e === "cloud.upload" ? Object.keys(t).every((s) => ["resource", "taskId"].includes(s)) && Object.prototype.hasOwnProperty.call(t, "resource") && I(t.resource) && (t.taskId === void 0 || i(t.taskId, 128)) : e === "files.pick" ? o(t, ["accept", "multiple"]) && Array.isArray(t.accept) && t.accept.length <= 16 && t.accept.every((s) => i(s, 128)) && typeof t.multiple == "boolean" : e === "files.write" ? o(t, ["name", "mime", "bytesBase64"]) && i(t.name, 512) && i(t.mime, 128) && i(t.bytesBase64, 32 * 1024 * 1024) : e === "ffmpeg.execute" ? o(t, ["taskId", "plan"]) && i(t.taskId, 128) && U(t.plan) : e === "ffmpeg.cancel" || e === "tasks.snapshot" || e === "tasks.cancel" ? o(t, ["taskId"]) && i(t.taskId, 128) : e === "downloads.start" ? o(t, ["resource", "name"]) && I(t.resource) && i(t.name, 256) : e === "downloads.cancel" ? o(t, ["downloadId"]) && i(t.downloadId, 128) : e === "tasks.create" ? o(t, ["taskId", "releaseId", "schedulerVersion", "planSnapshot", "state", "lastEventSeq"]) && i(t.taskId, 128) && i(t.releaseId, 128) && i(t.schedulerVersion, 32) && c(t.planSnapshot) && S(t.planSnapshot) && t.state === "queued" && t.lastEventSeq === 0 : e === "tasks.appendEvent" ? o(t, ["taskId", "event"]) && i(t.taskId, 128) && T(t.event) && t.taskId === t.event.taskId : e === "cloud.download" ? o(t, ["url", "name"]) && w(t.url) && i(t.name, 256) : e === "cloud.executeTask" ? o(t, ["taskId", "entityId", "input", "execution"]) && i(t.taskId, 128) && i(t.entityId, 128) && c(t.input) && S(t.input) && ["sync", "async"].includes(String(t.execution)) : e === "transport.subscribeTask" ? o(t, ["taskId", "afterSeq"]) && i(t.taskId, 128) && p(t.afterSeq, 0) : e === "transport.unsubscribeTask" ? o(t, ["subscriptionId"]) && i(t.subscriptionId, 128) : e === "settings.get" ? o(t, ["key"]) && i(t.key, 128) : o(t, ["key", "value"]) && i(t.key, 128) && ["string", "number", "boolean"].includes(typeof t.value) : !1;
|
|
98
|
+
}
|
|
99
|
+
function P(e) {
|
|
100
|
+
return !c(e) || !o(e, ["requestId", "contractVersion", "capability", "payload"]) || !i(e.requestId, 128) || e.contractVersion !== m || !i(e.capability, 128) ? { ok: !1, issue: "invalid envelope" } : N.includes(e.capability) ? B(e.capability, e.payload) ? { ok: !0, value: e } : { ok: !1, issue: "invalid payload" } : { ok: !1, issue: "unknown capability" };
|
|
101
|
+
}
|
|
102
|
+
function K(e, t) {
|
|
103
|
+
return T(e) ? !t && !["queued", "running", "cancelled"].includes(e.type) ? { ok: !1, issue: "invalid initial task state transition" } : t && (t.taskId !== e.taskId || e.seq !== t.seq + 1 || t.eventId === e.eventId || _.has(t.type)) ? { ok: !1, issue: "invalid task event sequence" } : (t == null ? void 0 : t.type) === "queued" && !["running", "log", "cancelled", "failed"].includes(e.type) ? { ok: !1, issue: "invalid queued task transition" } : t && ["running", "stage.started", "stage.progress", "stage.retry", "log"].includes(t.type) && !["stage.started", "stage.progress", "stage.retry", "log", "completed", "failed", "cancelled"].includes(e.type) ? { ok: !1, issue: "invalid running task transition" } : { ok: !0, value: e } : { ok: !1, issue: "invalid task event" };
|
|
104
|
+
}
|
|
105
|
+
function Z(e) {
|
|
106
|
+
return c(e) && o(e, ["subscriptionId", "taskId", "type", "event"]) && i(e.subscriptionId, 128) && i(e.taskId, 128) && e.type === "task.event" && T(e.event) && e.taskId === e.event.taskId ? { ok: !0, value: e } : { ok: !1, issue: "invalid host event" };
|
|
107
|
+
}
|
|
108
|
+
function q(e) {
|
|
109
|
+
return c(e) && o(e, ["taskId", "releaseId", "schedulerVersion", "planSnapshot", "state", "lastEventSeq"]) && i(e.taskId, 128) && i(e.releaseId, 128) && i(e.schedulerVersion, 32) && c(e.planSnapshot) && S(e.planSnapshot) && ["queued", "running", "completed", "failed", "cancelled"].includes(String(e.state)) && p(e.lastEventSeq, 0);
|
|
110
|
+
}
|
|
111
|
+
function J(e, t) {
|
|
112
|
+
return e === "tasks.list" ? Array.isArray(t) && t.every(q) : c(t) ? ["navigation.openExternal", "navigation.close", "navigation.reveal", "transport.unsubscribeTask", "settings.set"].includes(e) ? o(t, []) : e === "system.getRuntimeInfo" ? o(t, ["platform", "contractVersion", "capabilities"]) && ["web", "electron"].includes(String(t.platform)) && t.contractVersion === m && Array.isArray(t.capabilities) && t.capabilities.every((s) => N.includes(s)) : e === "files.pick" ? o(t, ["resources"]) && Array.isArray(t.resources) && t.resources.every(I) : e === "files.read" ? o(t, ["bytesBase64"]) && typeof t.bytesBase64 == "string" && t.bytesBase64.length <= 32 * 1024 * 1024 : e === "files.write" || e === "cloud.download" ? o(t, ["resource"]) && I(t.resource) : e === "files.stat" ? o(t, ["name", "mime", "size"]) && i(t.name, 512) && i(t.mime, 128) && p(t.size, 0, 1024 * 1024 * 1024 * 16) : e === "files.removeTemp" ? o(t, ["removed"]) && i(t.removed, 128) : e === "ffmpeg.execute" ? o(t, ["outputs", "exitCode"]) && Array.isArray(t.outputs) && t.outputs.every(I) && p(t.exitCode, 0, 255) : e === "ffmpeg.probe" ? o(t, ["durationSeconds", "streams"]) && (t.durationSeconds === null || typeof t.durationSeconds == "number" && t.durationSeconds >= 0) && Array.isArray(t.streams) && t.streams.every((s) => c(s) && o(s, ["codec", "kind"]) && i(s.codec, 64) && ["video", "audio", "other"].includes(String(s.kind))) : e === "ffmpeg.cancel" || e === "tasks.cancel" ? o(t, ["cancelled"]) && i(t.cancelled, 128) : e === "downloads.start" ? o(t, ["downloadId"]) && i(t.downloadId, 128) : e === "downloads.cancel" ? o(t, ["cancelled"]) && i(t.cancelled, 128) : e === "tasks.create" ? q(t) : e === "tasks.appendEvent" ? o(t, ["acceptedSeq"]) && p(t.acceptedSeq, 1) : e === "tasks.snapshot" ? o(t, ["snapshot", "events"]) && (t.snapshot === null || q(t.snapshot)) && Array.isArray(t.events) && t.events.every(T) : e === "tasks.clear" ? o(t, ["cleared"]) && p(t.cleared, 0) : e === "cloud.upload" ? o(t, ["key", "backend"]) && i(t.key, 1024) && ["tencent-cos", "aliyun-oss"].includes(String(t.backend)) : e === "cloud.executeTask" ? o(t, ["backendTaskId", "output"]) && (t.backendTaskId === null || i(t.backendTaskId, 128)) && (t.output === null || c(t.output) && z(t.output, 64 * 1024)) : e === "transport.subscribeTask" ? o(t, ["subscriptionId"]) && i(t.subscriptionId, 128) : e === "settings.get" ? o(t, ["value"]) && (t.value === null || ["string", "number", "boolean"].includes(typeof t.value)) : !1 : !1;
|
|
113
|
+
}
|
|
114
|
+
function Q(e, t) {
|
|
115
|
+
if (!c(t) || !i(t.requestId, 128) || t.contractVersion !== m || typeof t.ok != "boolean") return { ok: !1, issue: "invalid host response envelope" };
|
|
116
|
+
if (t.ok) return o(t, ["requestId", "contractVersion", "ok", "data"]) && J(e, t.data) ? { ok: !0, value: t } : { ok: !1, issue: "invalid host response data" };
|
|
117
|
+
const s = t.error;
|
|
118
|
+
return o(t, ["requestId", "contractVersion", "ok", "error"]) && c(s) && o(s, ["code", "message", "retryable"]) && ["INVALID_REQUEST", "CONTRACT_VERSION_MISMATCH", "CAPABILITY_DENIED", "RESOURCE_DENIED", "NOT_FOUND", "CANCELLED", "CONFLICT", "INTERNAL"].includes(String(s.code)) && i(s.message, 1024) && typeof s.retryable == "boolean" ? { ok: !0, value: t } : { ok: !1, issue: "invalid host response error" };
|
|
119
|
+
}
|
|
120
|
+
function G(e) {
|
|
121
|
+
const t = c(e) && typeof e.issuedAt == "string" ? Date.parse(e.issuedAt) : Number.NaN;
|
|
122
|
+
if (!c(e) || !o(e, ["releaseId", "contractVersion", "uiEntry", "schedulerEntry", "assets", "requiredCapabilities", "issuedAt", "keyId", "signature"]) || !i(e.releaseId, 128) || e.contractVersion !== m || !w(e.uiEntry) || !w(e.schedulerEntry) || !Array.isArray(e.assets) || !Array.isArray(e.requiredCapabilities) || !i(e.issuedAt, 64) || Number.isNaN(t) || t > Date.now() + 3e5 || Date.now() - t > 1e3 * 60 * 60 * 24 * 30 || !i(e.keyId, 128) || !/^[A-Za-z0-9._-]+$/.test(e.keyId) || !i(e.signature, 8192)) return { ok: !1, issue: "invalid Remote manifest envelope" };
|
|
123
|
+
const s = /* @__PURE__ */ new Set();
|
|
124
|
+
for (const r of e.assets) {
|
|
125
|
+
if (!c(r) || !o(r, ["url", "size", "sha256", "kind", "contentType"]) || !w(r.url) || !p(r.size, 0, 512 * 1024 * 1024) || !/^[a-f0-9]{64}$/i.test(String(r.sha256)) || !["js", "css", "wasm", "asset"].includes(String(r.kind)) || !i(r.contentType, 128) || s.has(r.url) || r.kind === "js" && !["text/javascript", "application/javascript"].includes(String(r.contentType)) || r.kind === "css" && r.contentType !== "text/css" || r.kind === "wasm" && r.contentType !== "application/wasm") return { ok: !1, issue: "invalid Remote asset" };
|
|
126
|
+
s.add(r.url);
|
|
127
|
+
}
|
|
128
|
+
const d = e.assets.filter((r) => r.url === e.uiEntry || r.url === e.schedulerEntry);
|
|
129
|
+
return !s.has(e.uiEntry) || !s.has(e.schedulerEntry) || d.some((r) => r.kind !== "js") || !e.requiredCapabilities.every((r) => N.includes(r)) ? { ok: !1, issue: "invalid Remote manifest references" } : { ok: !0, value: e };
|
|
130
|
+
}
|
|
131
|
+
function v(e) {
|
|
132
|
+
return {
|
|
133
|
+
invoke: async (t) => {
|
|
134
|
+
const s = P(t), d = t && typeof t == "object" ? t : {}, r = typeof d.requestId == "string" && d.requestId.length > 0 && d.requestId.length <= 128 ? d.requestId : "invalid-request";
|
|
135
|
+
if (d.contractVersion !== m)
|
|
136
|
+
return { requestId: r, contractVersion: m, ok: !1, error: { code: "CONTRACT_VERSION_MISMATCH", message: "Host Contract v2 is required", retryable: !1 } };
|
|
137
|
+
if (!s.ok) return { requestId: r, contractVersion: m, ok: !1, error: { code: "INVALID_REQUEST", message: s.issue, retryable: !1 } };
|
|
138
|
+
try {
|
|
139
|
+
const l = await e.invoke(s.value), g = Q(t.capability, l);
|
|
140
|
+
return !g.ok || l.requestId !== t.requestId ? { requestId: r, contractVersion: m, ok: !1, error: { code: "INTERNAL", message: "Host returned an invalid Contract v2 response", retryable: !1 } } : g.value;
|
|
141
|
+
} catch (l) {
|
|
142
|
+
return { requestId: r, contractVersion: m, ok: !1, error: { code: "INTERNAL", message: l instanceof Error ? l.message : "Host transport failed", retryable: !0 } };
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
subscribe(t) {
|
|
146
|
+
return e.subscribe((s) => {
|
|
147
|
+
const d = Z(s);
|
|
148
|
+
d.ok && t(d.value);
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
async cancel(t) {
|
|
152
|
+
if (typeof t != "string" || t.length < 1 || t.length > 128) throw new Error("invalid requestId");
|
|
153
|
+
await e.cancel(t);
|
|
154
|
+
},
|
|
155
|
+
async dispose() {
|
|
156
|
+
var t;
|
|
157
|
+
await ((t = e.dispose) == null ? void 0 : t.call(e));
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function X(e) {
|
|
162
|
+
return [...new Uint8Array(e)].map((t) => t.toString(16).padStart(2, "0")).join("");
|
|
163
|
+
}
|
|
164
|
+
function Y(e, t) {
|
|
165
|
+
return t.includes(new URL(e).origin);
|
|
166
|
+
}
|
|
167
|
+
async function ee(e, t) {
|
|
168
|
+
const s = G(e);
|
|
169
|
+
if (!s.ok) throw new Error(s.issue);
|
|
170
|
+
if (!e.requiredCapabilities.every((r) => t.capabilities.includes(r))) throw new Error("Remote capability is not available");
|
|
171
|
+
if (!await t.verifySignature(e)) throw new Error("Remote signature is invalid");
|
|
172
|
+
const d = /* @__PURE__ */ new Map();
|
|
173
|
+
for (const r of e.assets) {
|
|
174
|
+
if (!Y(r.url, t.allowOrigins) || r.size < 0 || !/^[a-f0-9]{64}$/i.test(r.sha256)) throw new Error("Remote asset is not allowed");
|
|
175
|
+
const l = await t.fetcher(r.url);
|
|
176
|
+
if (l.contentType.split(";", 1)[0].trim().toLowerCase() !== r.contentType.toLowerCase()) throw new Error(`Remote asset content-type mismatch: ${r.url}`);
|
|
177
|
+
if (l.bytes.byteLength !== r.size) throw new Error(`Remote asset size mismatch: ${r.url}`);
|
|
178
|
+
if (X(await crypto.subtle.digest("SHA-256", l.bytes)) !== r.sha256.toLowerCase()) throw new Error(`Remote asset hash mismatch: ${r.url}`);
|
|
179
|
+
d.set(r.url, l.bytes);
|
|
180
|
+
}
|
|
181
|
+
if (!d.has(e.uiEntry) || !d.has(e.schedulerEntry)) throw new Error("Remote entry is not declared as an asset");
|
|
182
|
+
return { manifest: e, assets: d };
|
|
183
|
+
}
|
|
184
|
+
class te {
|
|
185
|
+
constructor() {
|
|
186
|
+
E(this, "snapshots", /* @__PURE__ */ new Map());
|
|
187
|
+
E(this, "events", /* @__PURE__ */ new Map());
|
|
188
|
+
E(this, "requests", /* @__PURE__ */ new Map());
|
|
189
|
+
}
|
|
190
|
+
fingerprint(t) {
|
|
191
|
+
const s = (d) => Array.isArray(d) ? `[${d.map(s).join(",")}]` : d && typeof d == "object" ? `{${Object.entries(d).sort(([r], [l]) => r.localeCompare(l)).map(([r, l]) => `${JSON.stringify(r)}:${s(l)}`).join(",")}}` : JSON.stringify(d) ?? "null";
|
|
192
|
+
return s(t);
|
|
193
|
+
}
|
|
194
|
+
repeated(t, s, d) {
|
|
195
|
+
const r = this.requests.get(t);
|
|
196
|
+
if (r) {
|
|
197
|
+
if (r.operation !== s || r.fingerprint !== this.fingerprint(d)) throw new Error("CONFLICT: requestId replay payload differs");
|
|
198
|
+
return r.result;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
apply(t) {
|
|
202
|
+
const s = this.snapshots.get(t.taskId);
|
|
203
|
+
if (!s) throw new Error("task not found");
|
|
204
|
+
const d = this.events.get(t.taskId) || [], r = K(t, d.at(-1) || null);
|
|
205
|
+
if (!r.ok) throw new Error(r.issue);
|
|
206
|
+
d.push(t), this.events.set(t.taskId, d);
|
|
207
|
+
const l = t.type === "running" ? "running" : t.type === "completed" ? "completed" : t.type === "failed" ? "failed" : t.type === "cancelled" ? "cancelled" : s.state;
|
|
208
|
+
return this.snapshots.set(t.taskId, { ...s, state: l, lastEventSeq: t.seq }), t.seq;
|
|
209
|
+
}
|
|
210
|
+
create(t) {
|
|
211
|
+
const s = this.snapshots.get(t.taskId);
|
|
212
|
+
return s || (this.snapshots.set(t.taskId, t), this.events.set(t.taskId, []), t);
|
|
213
|
+
}
|
|
214
|
+
append(t, s) {
|
|
215
|
+
const d = this.repeated(t, "append", s);
|
|
216
|
+
if (d !== void 0) return d;
|
|
217
|
+
const r = this.apply(s);
|
|
218
|
+
return this.requests.set(t, { operation: "append", fingerprint: this.fingerprint(s), result: r }), r;
|
|
219
|
+
}
|
|
220
|
+
cancel(t, s, d) {
|
|
221
|
+
const r = this.repeated(t, "cancel", { taskId: s });
|
|
222
|
+
if (r !== void 0) return r;
|
|
223
|
+
const l = this.snapshots.get(s);
|
|
224
|
+
if (!l) throw new Error("task not found");
|
|
225
|
+
const g = this.apply({ eventId: t, taskId: s, seq: l.lastEventSeq + 1, at: d, type: "cancelled", data: {} });
|
|
226
|
+
return this.requests.set(t, { operation: "cancel", fingerprint: this.fingerprint({ taskId: s }), result: g }), g;
|
|
227
|
+
}
|
|
228
|
+
read(t) {
|
|
229
|
+
return { snapshot: this.snapshots.get(t) || null, events: [...this.events.get(t) || []] };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const se = [
|
|
233
|
+
["system.getRuntimeInfo", !1],
|
|
234
|
+
["navigation.openExternal", !1],
|
|
235
|
+
["navigation.close", !1],
|
|
236
|
+
["navigation.reveal", !1],
|
|
237
|
+
["files.pick", !1],
|
|
238
|
+
["files.read", !1],
|
|
239
|
+
["files.write", !1],
|
|
240
|
+
["files.stat", !1],
|
|
241
|
+
["files.removeTemp", !1],
|
|
242
|
+
["ffmpeg.execute", !0],
|
|
243
|
+
["ffmpeg.probe", !1],
|
|
244
|
+
["ffmpeg.cancel", !0],
|
|
245
|
+
["downloads.start", !1],
|
|
246
|
+
["downloads.cancel", !1],
|
|
247
|
+
["tasks.create", !0],
|
|
248
|
+
["tasks.appendEvent", !0],
|
|
249
|
+
["tasks.snapshot", !1],
|
|
250
|
+
["tasks.list", !1],
|
|
251
|
+
["tasks.cancel", !0],
|
|
252
|
+
["tasks.clear", !1],
|
|
253
|
+
["cloud.upload", !0],
|
|
254
|
+
["cloud.download", !1],
|
|
255
|
+
["cloud.executeTask", !0],
|
|
256
|
+
["transport.subscribeTask", !1],
|
|
257
|
+
["transport.unsubscribeTask", !1],
|
|
258
|
+
["settings.get", !1],
|
|
259
|
+
["settings.set", !1]
|
|
260
|
+
].map(([e, t]) => ({ capability: e, response: !0, event: t })), re = {
|
|
261
|
+
requestId: "fixture-runtime-info",
|
|
262
|
+
contractVersion: m,
|
|
263
|
+
capability: "system.getRuntimeInfo",
|
|
264
|
+
payload: {}
|
|
265
|
+
}, ne = {
|
|
266
|
+
requestId: "fixture-traversal",
|
|
267
|
+
contractVersion: m,
|
|
268
|
+
capability: "files.read",
|
|
269
|
+
payload: { resource: { id: "x", name: "x", mime: "text/plain", size: 1, uri: "../secret" } }
|
|
270
|
+
}, oe = {
|
|
271
|
+
releaseId: "fixture-release",
|
|
272
|
+
contractVersion: m,
|
|
273
|
+
uiEntry: "https://remote.example.test/runtime.js",
|
|
274
|
+
schedulerEntry: "https://remote.example.test/runtime.js",
|
|
275
|
+
assets: [{ url: "https://remote.example.test/runtime.js", size: 0, sha256: "0".repeat(64), kind: "js", contentType: "text/javascript" }],
|
|
276
|
+
requiredCapabilities: ["system.getRuntimeInfo"],
|
|
277
|
+
issuedAt: "2026-01-01T00:00:00.000Z",
|
|
278
|
+
keyId: "fixture",
|
|
279
|
+
signature: "fixture"
|
|
280
|
+
}, ie = [
|
|
281
|
+
"system.getRuntimeInfo",
|
|
282
|
+
"files.pick",
|
|
283
|
+
"files.read",
|
|
284
|
+
"files.write",
|
|
285
|
+
"files.removeTemp",
|
|
286
|
+
"ffmpeg.execute",
|
|
287
|
+
"ffmpeg.probe",
|
|
288
|
+
"downloads.start",
|
|
289
|
+
"tasks.create",
|
|
290
|
+
"tasks.appendEvent",
|
|
291
|
+
"tasks.list",
|
|
292
|
+
"tasks.cancel",
|
|
293
|
+
"cloud.upload",
|
|
294
|
+
"cloud.download",
|
|
295
|
+
"cloud.executeTask",
|
|
296
|
+
"transport.subscribeTask",
|
|
297
|
+
"transport.unsubscribeTask"
|
|
298
|
+
];
|
|
299
|
+
export {
|
|
300
|
+
m as CONTRACT_VERSION_V2,
|
|
301
|
+
ie as REMOTE_PRODUCT_REQUIRED_CAPABILITIES,
|
|
302
|
+
te as TaskLedgerV2,
|
|
303
|
+
se as capabilityMatrix,
|
|
304
|
+
v as createHostClientV2,
|
|
305
|
+
ne as invalidTraversalRequest,
|
|
306
|
+
oe as remoteManifestFixture,
|
|
307
|
+
re as validRuntimeInfoRequest,
|
|
308
|
+
Z as validateHostEvent,
|
|
309
|
+
P as validateHostRequest,
|
|
310
|
+
Q as validateHostResponse,
|
|
311
|
+
G as validateRemoteManifest,
|
|
312
|
+
K as validateTaskEvent,
|
|
313
|
+
ee as verifyRemoteRelease
|
|
314
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type HostCapability, type RemoteManifestV2 } from './types.ts';
|
|
2
|
+
export interface VerifiedRemoteRelease {
|
|
3
|
+
manifest: RemoteManifestV2;
|
|
4
|
+
assets: Map<string, Uint8Array>;
|
|
5
|
+
}
|
|
6
|
+
export interface RemoteVerificationOptions {
|
|
7
|
+
allowOrigins: string[];
|
|
8
|
+
capabilities: HostCapability[];
|
|
9
|
+
verifySignature(manifest: RemoteManifestV2): Promise<boolean>;
|
|
10
|
+
fetcher(url: string): Promise<{
|
|
11
|
+
bytes: Uint8Array;
|
|
12
|
+
contentType: string;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
export declare function verifyRemoteRelease(manifest: RemoteManifestV2, options: RemoteVerificationOptions): Promise<VerifiedRemoteRelease>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HostCapability } from './types.ts';
|
|
2
|
+
export interface CapabilityMatrixRow {
|
|
3
|
+
capability: HostCapability;
|
|
4
|
+
response: true;
|
|
5
|
+
event: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Single audit source: every v2 invocation has a response; task lifecycle changes emit an event. */
|
|
8
|
+
export declare const capabilityMatrix: readonly CapabilityMatrixRow[];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** Audited directly against Remote Product Runtime's production Host calls. */
|
|
2
|
+
export declare const REMOTE_PRODUCT_REQUIRED_CAPABILITIES: readonly ["system.getRuntimeInfo", "files.pick", "files.read", "files.write", "files.removeTemp", "ffmpeg.execute", "ffmpeg.probe", "downloads.start", "tasks.create", "tasks.appendEvent", "tasks.list", "tasks.cancel", "cloud.upload", "cloud.download", "cloud.executeTask", "transport.subscribeTask", "transport.unsubscribeTask"];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type HostCapability, type HostEvent, type HostRequest, type HostResponse, type RemoteManifestV2, type TaskEventRecordV2 } from './types.ts';
|
|
2
|
+
export type ValidationResult<T> = {
|
|
3
|
+
ok: true;
|
|
4
|
+
value: T;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
issue: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function validateHostRequest(input: unknown): ValidationResult<HostRequest>;
|
|
10
|
+
export declare function validateTaskEvent(recordValue: unknown, previous: TaskEventRecordV2 | null): ValidationResult<TaskEventRecordV2>;
|
|
11
|
+
export declare function validateHostEvent(input: unknown): ValidationResult<HostEvent>;
|
|
12
|
+
export declare function validateHostResponse(capability: HostCapability, input: unknown): ValidationResult<HostResponse>;
|
|
13
|
+
export declare function validateRemoteManifest(input: unknown): ValidationResult<RemoteManifestV2>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TaskEventRecordV2, TaskSnapshotV2 } from './types.ts';
|
|
2
|
+
export declare class TaskLedgerV2 {
|
|
3
|
+
private readonly snapshots;
|
|
4
|
+
private readonly events;
|
|
5
|
+
private readonly requests;
|
|
6
|
+
private fingerprint;
|
|
7
|
+
private repeated;
|
|
8
|
+
private apply;
|
|
9
|
+
create(snapshot: TaskSnapshotV2): TaskSnapshotV2;
|
|
10
|
+
append(requestId: string, event: TaskEventRecordV2): number;
|
|
11
|
+
cancel(requestId: string, taskId: string, at: string): number;
|
|
12
|
+
read(taskId: string): {
|
|
13
|
+
snapshot: TaskSnapshotV2 | null;
|
|
14
|
+
events: TaskEventRecordV2[];
|
|
15
|
+
};
|
|
16
|
+
}
|