@tier0/sdk-v2 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/NOTICE.md +7 -0
- package/README.md +201 -2
- package/dist/cjs/app-identity-contract.generated.d.ts +22 -0
- package/dist/cjs/app-identity-contract.generated.js +51 -0
- package/dist/cjs/app-identity-contract.generated.js.map +1 -0
- package/dist/cjs/capabilities.d.ts +54 -0
- package/dist/cjs/capabilities.js +134 -0
- package/dist/cjs/capabilities.js.map +1 -0
- package/dist/cjs/client.d.ts +604 -0
- package/dist/cjs/client.js +35 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/cloud-server.d.ts +31 -0
- package/dist/cjs/cloud-server.js +114 -0
- package/dist/cjs/cloud-server.js.map +1 -0
- package/dist/cjs/cloud-transport.d.ts +67 -0
- package/dist/cjs/cloud-transport.js +272 -0
- package/dist/cjs/cloud-transport.js.map +1 -0
- package/dist/cjs/controls.d.ts +93 -0
- package/dist/cjs/controls.js +169 -0
- package/dist/cjs/controls.js.map +1 -0
- package/dist/cjs/data/bootstrap.d.ts +70 -0
- package/dist/cjs/data/bootstrap.js +291 -0
- package/dist/cjs/data/bootstrap.js.map +1 -0
- package/dist/cjs/data/call.d.ts +33 -0
- package/dist/cjs/data/call.js +216 -0
- package/dist/cjs/data/call.js.map +1 -0
- package/dist/cjs/data/client.d.ts +134 -0
- package/dist/cjs/data/client.js +185 -0
- package/dist/cjs/data/client.js.map +1 -0
- package/dist/cjs/data/collection.d.ts +335 -0
- package/dist/cjs/data/collection.js +601 -0
- package/dist/cjs/data/collection.js.map +1 -0
- package/dist/cjs/data/context.d.ts +12 -0
- package/dist/cjs/data/context.js +50 -0
- package/dist/cjs/data/context.js.map +1 -0
- package/dist/cjs/data/declarations.d.ts +11 -0
- package/dist/cjs/data/declarations.js +18 -0
- package/dist/cjs/data/declarations.js.map +1 -0
- package/dist/cjs/data/define.d.ts +77 -0
- package/dist/cjs/data/define.js +31 -0
- package/dist/cjs/data/define.js.map +1 -0
- package/dist/cjs/data/error.d.ts +78 -0
- package/dist/cjs/data/error.js +182 -0
- package/dist/cjs/data/error.js.map +1 -0
- package/dist/cjs/data/index.d.ts +24 -0
- package/dist/cjs/data/index.js +49 -0
- package/dist/cjs/data/index.js.map +1 -0
- package/dist/cjs/data/schema.d.ts +88 -0
- package/dist/cjs/data/schema.js +657 -0
- package/dist/cjs/data/schema.js.map +1 -0
- package/dist/cjs/data/sort.d.ts +8 -0
- package/dist/cjs/data/sort.js +21 -0
- package/dist/cjs/data/sort.js.map +1 -0
- package/dist/cjs/data/subscribe.d.ts +108 -0
- package/dist/cjs/data/subscribe.js +270 -0
- package/dist/cjs/data/subscribe.js.map +1 -0
- package/dist/cjs/files.d.ts +67 -0
- package/dist/cjs/files.js +119 -0
- package/dist/cjs/files.js.map +1 -0
- package/dist/cjs/framework-scope.d.ts +1 -0
- package/dist/cjs/framework-scope.js +14 -0
- package/dist/cjs/framework-scope.js.map +1 -0
- package/dist/cjs/index.d.ts +14 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/mq/broker.d.ts +65 -0
- package/dist/cjs/mq/broker.js +115 -0
- package/dist/cjs/mq/broker.js.map +1 -0
- package/dist/cjs/mq/client.d.ts +37 -0
- package/dist/cjs/mq/client.js +321 -0
- package/dist/cjs/mq/client.js.map +1 -0
- package/dist/cjs/mq/index.d.ts +5 -0
- package/dist/cjs/mq/index.js +11 -0
- package/dist/cjs/mq/index.js.map +1 -0
- package/dist/cjs/mq/types.d.ts +48 -0
- package/dist/cjs/mq/types.js +3 -0
- package/dist/cjs/mq/types.js.map +1 -0
- package/dist/cjs/openapi/api.generated.d.ts +820 -0
- package/dist/cjs/openapi/api.generated.js +607 -0
- package/dist/cjs/openapi/api.generated.js.map +1 -0
- package/dist/cjs/openapi/client.d.ts +56 -0
- package/dist/cjs/openapi/client.js +219 -0
- package/dist/cjs/openapi/client.js.map +1 -0
- package/dist/cjs/openapi/codecs.generated.d.ts +2234 -0
- package/dist/cjs/openapi/codecs.generated.js +6 -0
- package/dist/cjs/openapi/codecs.generated.js.map +1 -0
- package/dist/cjs/openapi/index.d.ts +5 -0
- package/dist/cjs/openapi/index.js +12 -0
- package/dist/cjs/openapi/index.js.map +1 -0
- package/dist/cjs/openapi/types.generated.d.ts +3227 -0
- package/dist/cjs/openapi/types.generated.js +3 -0
- package/dist/cjs/openapi/types.generated.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/react.d.ts +9 -0
- package/dist/cjs/react.js +16 -0
- package/dist/cjs/react.js.map +1 -0
- package/dist/cjs/runtime-context.d.ts +9 -0
- package/dist/cjs/runtime-context.js +25 -0
- package/dist/cjs/runtime-context.js.map +1 -0
- package/dist/cjs/runtime-env.d.ts +1 -0
- package/dist/cjs/runtime-env.js +18 -0
- package/dist/cjs/runtime-env.js.map +1 -0
- package/dist/cjs/source.d.ts +39 -0
- package/dist/cjs/source.js +29 -0
- package/dist/cjs/source.js.map +1 -0
- package/dist/cjs/stream.d.ts +40 -0
- package/dist/cjs/stream.js +33 -0
- package/dist/cjs/stream.js.map +1 -0
- package/dist/cjs/uns-v2/client.d.ts +132 -0
- package/dist/cjs/uns-v2/client.js +352 -0
- package/dist/cjs/uns-v2/client.js.map +1 -0
- package/dist/cjs/uns-v2/codec.d.ts +11 -0
- package/dist/cjs/uns-v2/codec.js +290 -0
- package/dist/cjs/uns-v2/codec.js.map +1 -0
- package/dist/cjs/uns-v2/data-client.d.ts +10 -0
- package/dist/cjs/uns-v2/data-client.js +18 -0
- package/dist/cjs/uns-v2/data-client.js.map +1 -0
- package/dist/cjs/uns-v2/generated.d.ts +18178 -0
- package/dist/cjs/uns-v2/generated.js +144 -0
- package/dist/cjs/uns-v2/generated.js.map +1 -0
- package/dist/cjs/uns-v2/index.d.ts +5 -0
- package/dist/cjs/uns-v2/index.js +24 -0
- package/dist/cjs/uns-v2/index.js.map +1 -0
- package/dist/cjs/uns-v2/sse.d.ts +20 -0
- package/dist/cjs/uns-v2/sse.js +65 -0
- package/dist/cjs/uns-v2/sse.js.map +1 -0
- package/dist/cjs/vue.d.ts +9 -0
- package/dist/cjs/vue.js +39 -0
- package/dist/cjs/vue.js.map +1 -0
- package/dist/esm/app-identity-contract.generated.d.ts +22 -0
- package/dist/esm/app-identity-contract.generated.js +48 -0
- package/dist/esm/app-identity-contract.generated.js.map +1 -0
- package/dist/esm/capabilities.d.ts +54 -0
- package/dist/esm/capabilities.js +129 -0
- package/dist/esm/capabilities.js.map +1 -0
- package/dist/esm/client.d.ts +604 -0
- package/dist/esm/client.js +32 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/cloud-server.d.ts +31 -0
- package/dist/esm/cloud-server.js +109 -0
- package/dist/esm/cloud-server.js.map +1 -0
- package/dist/esm/cloud-transport.d.ts +67 -0
- package/dist/esm/cloud-transport.js +267 -0
- package/dist/esm/cloud-transport.js.map +1 -0
- package/dist/esm/controls.d.ts +93 -0
- package/dist/esm/controls.js +163 -0
- package/dist/esm/controls.js.map +1 -0
- package/dist/esm/data/bootstrap.d.ts +70 -0
- package/dist/esm/data/bootstrap.js +286 -0
- package/dist/esm/data/bootstrap.js.map +1 -0
- package/dist/esm/data/call.d.ts +33 -0
- package/dist/esm/data/call.js +211 -0
- package/dist/esm/data/call.js.map +1 -0
- package/dist/esm/data/client.d.ts +134 -0
- package/dist/esm/data/client.js +181 -0
- package/dist/esm/data/client.js.map +1 -0
- package/dist/esm/data/collection.d.ts +335 -0
- package/dist/esm/data/collection.js +594 -0
- package/dist/esm/data/collection.js.map +1 -0
- package/dist/esm/data/context.d.ts +12 -0
- package/dist/esm/data/context.js +44 -0
- package/dist/esm/data/context.js.map +1 -0
- package/dist/esm/data/declarations.d.ts +11 -0
- package/dist/esm/data/declarations.js +10 -0
- package/dist/esm/data/declarations.js.map +1 -0
- package/dist/esm/data/define.d.ts +77 -0
- package/dist/esm/data/define.js +27 -0
- package/dist/esm/data/define.js.map +1 -0
- package/dist/esm/data/error.d.ts +78 -0
- package/dist/esm/data/error.js +176 -0
- package/dist/esm/data/error.js.map +1 -0
- package/dist/esm/data/index.d.ts +24 -0
- package/dist/esm/data/index.js +20 -0
- package/dist/esm/data/index.js.map +1 -0
- package/dist/esm/data/schema.d.ts +88 -0
- package/dist/esm/data/schema.js +646 -0
- package/dist/esm/data/schema.js.map +1 -0
- package/dist/esm/data/sort.d.ts +8 -0
- package/dist/esm/data/sort.js +18 -0
- package/dist/esm/data/sort.js.map +1 -0
- package/dist/esm/data/subscribe.d.ts +108 -0
- package/dist/esm/data/subscribe.js +265 -0
- package/dist/esm/data/subscribe.js.map +1 -0
- package/dist/esm/files.d.ts +67 -0
- package/dist/esm/files.js +113 -0
- package/dist/esm/files.js.map +1 -0
- package/dist/esm/framework-scope.d.ts +1 -0
- package/dist/esm/framework-scope.js +11 -0
- package/dist/esm/framework-scope.js.map +1 -0
- package/dist/esm/index.d.ts +14 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mq/broker.d.ts +65 -0
- package/dist/esm/mq/broker.js +109 -0
- package/dist/esm/mq/broker.js.map +1 -0
- package/dist/esm/mq/client.d.ts +37 -0
- package/dist/esm/mq/client.js +314 -0
- package/dist/esm/mq/client.js.map +1 -0
- package/dist/esm/mq/index.d.ts +5 -0
- package/dist/esm/mq/index.js +3 -0
- package/dist/esm/mq/index.js.map +1 -0
- package/dist/esm/mq/types.d.ts +48 -0
- package/dist/esm/mq/types.js +2 -0
- package/dist/esm/mq/types.js.map +1 -0
- package/dist/esm/openapi/api.generated.d.ts +820 -0
- package/dist/esm/openapi/api.generated.js +603 -0
- package/dist/esm/openapi/api.generated.js.map +1 -0
- package/dist/esm/openapi/client.d.ts +56 -0
- package/dist/esm/openapi/client.js +210 -0
- package/dist/esm/openapi/client.js.map +1 -0
- package/dist/esm/openapi/codecs.generated.d.ts +2234 -0
- package/dist/esm/openapi/codecs.generated.js +3 -0
- package/dist/esm/openapi/codecs.generated.js.map +1 -0
- package/dist/esm/openapi/index.d.ts +5 -0
- package/dist/esm/openapi/index.js +3 -0
- package/dist/esm/openapi/index.js.map +1 -0
- package/dist/esm/openapi/types.generated.d.ts +3227 -0
- package/dist/esm/openapi/types.generated.js +2 -0
- package/dist/esm/openapi/types.generated.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/react.d.ts +9 -0
- package/dist/esm/react.js +12 -0
- package/dist/esm/react.js.map +1 -0
- package/dist/esm/runtime-context.d.ts +9 -0
- package/dist/esm/runtime-context.js +22 -0
- package/dist/esm/runtime-context.js.map +1 -0
- package/dist/esm/runtime-env.d.ts +1 -0
- package/dist/esm/runtime-env.js +15 -0
- package/dist/esm/runtime-env.js.map +1 -0
- package/dist/esm/source.d.ts +39 -0
- package/dist/esm/source.js +25 -0
- package/dist/esm/source.js.map +1 -0
- package/dist/esm/stream.d.ts +40 -0
- package/dist/esm/stream.js +29 -0
- package/dist/esm/stream.js.map +1 -0
- package/dist/esm/uns-v2/client.d.ts +132 -0
- package/dist/esm/uns-v2/client.js +343 -0
- package/dist/esm/uns-v2/client.js.map +1 -0
- package/dist/esm/uns-v2/codec.d.ts +11 -0
- package/dist/esm/uns-v2/codec.js +284 -0
- package/dist/esm/uns-v2/codec.js.map +1 -0
- package/dist/esm/uns-v2/data-client.d.ts +10 -0
- package/dist/esm/uns-v2/data-client.js +14 -0
- package/dist/esm/uns-v2/data-client.js.map +1 -0
- package/dist/esm/uns-v2/generated.d.ts +18178 -0
- package/dist/esm/uns-v2/generated.js +141 -0
- package/dist/esm/uns-v2/generated.js.map +1 -0
- package/dist/esm/uns-v2/index.d.ts +5 -0
- package/dist/esm/uns-v2/index.js +5 -0
- package/dist/esm/uns-v2/index.js.map +1 -0
- package/dist/esm/uns-v2/sse.d.ts +20 -0
- package/dist/esm/uns-v2/sse.js +60 -0
- package/dist/esm/uns-v2/sse.js.map +1 -0
- package/dist/esm/vue.d.ts +9 -0
- package/dist/esm/vue.js +36 -0
- package/dist/esm/vue.js.map +1 -0
- package/docs/acceptance-2026-10-22.md +88 -0
- package/package.json +243 -4
- package/skills/tier0-sdk-v2/SKILL.md +66 -0
- package/skills/tier0-sdk-v2/references/integration.md +72 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/SKILL.md +73 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/references/results.md +45 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md +63 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/SKILL.md +58 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/consistency.md +70 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/errors.md +82 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/modeling.md +113 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +168 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/schema-evolution.md +36 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/SKILL.md +85 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/delete.md +22 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/download.md +49 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/multipart.md +42 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/upload.md +27 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/url.md +22 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/SKILL.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/app-members.md +41 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/platform-members.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/SKILL.md +78 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/references/quickstart.md +69 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/SKILL.md +42 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/get.md +34 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/send.md +72 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +38 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/changes.md +40 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +63 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/delete.md +47 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/protocols.md +36 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/read.md +34 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +37 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +62 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +43 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/delete.md +35 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +64 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/lifecycle.md +26 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/read.md +35 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/update.md +36 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md +64 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/info.md +23 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/whoami.md +21 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +55 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/data-workflows.md +69 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/delete.md +53 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/namespace.md +38 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/read.md +34 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/restore.md +39 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/update.md +62 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { HttpClient, type ClientConfig, type RequestOptions } from './openapi/client.js';
|
|
2
|
+
import type { components } from './openapi/types.generated.js';
|
|
3
|
+
type Schemas = components['schemas'];
|
|
4
|
+
export type UploadOptions = Omit<Schemas['AssetFileUploadReq'], 'fileName' | 'contentType' | 'size'> & RequestOptions;
|
|
5
|
+
export type UploadResult = Schemas['AssetFileUploadResp'];
|
|
6
|
+
export type MultipartResult = Schemas['AssetFileMultipartCompleteResp'];
|
|
7
|
+
export interface MultipartOptions extends UploadOptions {
|
|
8
|
+
partSize?: number;
|
|
9
|
+
onProgress?: (progress: {
|
|
10
|
+
uploadedBytes: number;
|
|
11
|
+
totalBytes: number;
|
|
12
|
+
}) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface MultipartSession {
|
|
15
|
+
fileKey: string;
|
|
16
|
+
uploadId: string;
|
|
17
|
+
parts: Schemas['AssetFileMultipartPart'][];
|
|
18
|
+
completionAttempted: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare class MultipartUploadError extends Error {
|
|
21
|
+
readonly session: MultipartSession;
|
|
22
|
+
readonly cause: unknown;
|
|
23
|
+
constructor(session: MultipartSession, cause: unknown);
|
|
24
|
+
}
|
|
25
|
+
export declare const MULTIPART_THRESHOLD_BYTES: number;
|
|
26
|
+
export declare const DEFAULT_MULTIPART_PART_SIZE: number;
|
|
27
|
+
/** All platform requests are scoped to this instance; storage requests never carry its API key. */
|
|
28
|
+
export declare class FilesClient {
|
|
29
|
+
private readonly http;
|
|
30
|
+
private readonly api;
|
|
31
|
+
readonly multipart: {
|
|
32
|
+
abort: (body: components["schemas"]["SdkassetsFilesMultipartAbortRequest"], options?: RequestOptions) => Promise<{
|
|
33
|
+
aborted: number | bigint;
|
|
34
|
+
}>;
|
|
35
|
+
complete: (body: components["schemas"]["SdkassetsFilesMultipartCompleteRequest"], options?: RequestOptions) => Promise<{
|
|
36
|
+
expiresAt?: number | bigint;
|
|
37
|
+
filePath: string;
|
|
38
|
+
fileUrl?: string;
|
|
39
|
+
sizeBytes: number | bigint;
|
|
40
|
+
}>;
|
|
41
|
+
init: (body: components["schemas"]["SdkassetsFilesMultipartInitRequest"], options?: RequestOptions) => Promise<{
|
|
42
|
+
expiresAt: number | bigint;
|
|
43
|
+
fileKey: string;
|
|
44
|
+
filePath: string;
|
|
45
|
+
partCount: number | bigint;
|
|
46
|
+
partSize: number | bigint;
|
|
47
|
+
uploadId: string;
|
|
48
|
+
}>;
|
|
49
|
+
partUrls: (body: components["schemas"]["SdkassetsFilesMultipartPartUrlsRequest"], options?: RequestOptions) => Promise<{
|
|
50
|
+
partUrls: components["schemas"]["AssetFileMultipartPartUrl"][];
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
constructor(http: HttpClient);
|
|
54
|
+
private storage;
|
|
55
|
+
upload(file: File, options?: UploadOptions): Promise<UploadResult | MultipartResult>;
|
|
56
|
+
uploadMultipart(file: File, options?: MultipartOptions): Promise<MultipartResult>;
|
|
57
|
+
url(query: Parameters<typeof this.api.url>[0], options?: RequestOptions): Promise<{
|
|
58
|
+
expiresAt?: number | bigint;
|
|
59
|
+
fileUrl: string;
|
|
60
|
+
}>;
|
|
61
|
+
delete(body: Schemas['AssetFileDeleteReq'], options?: RequestOptions): Promise<{
|
|
62
|
+
deleted: boolean;
|
|
63
|
+
}>;
|
|
64
|
+
download(query: Parameters<typeof this.api.url>[0], options?: RequestOptions): Promise<Response>;
|
|
65
|
+
}
|
|
66
|
+
export declare function createFilesClient(config?: ClientConfig): FilesClient;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FilesClient = exports.DEFAULT_MULTIPART_PART_SIZE = exports.MULTIPART_THRESHOLD_BYTES = exports.MultipartUploadError = void 0;
|
|
4
|
+
exports.createFilesClient = createFilesClient;
|
|
5
|
+
const client_js_1 = require("./openapi/client.js");
|
|
6
|
+
const api_generated_js_1 = require("./openapi/api.generated.js");
|
|
7
|
+
class MultipartUploadError extends Error {
|
|
8
|
+
session;
|
|
9
|
+
cause;
|
|
10
|
+
constructor(session, cause) {
|
|
11
|
+
super('Multipart upload interrupted. The session is retained; reconcile completion before retrying or aborting.');
|
|
12
|
+
this.session = session;
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
this.name = 'MultipartUploadError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.MultipartUploadError = MultipartUploadError;
|
|
18
|
+
exports.MULTIPART_THRESHOLD_BYTES = 100 * 1024 * 1024;
|
|
19
|
+
exports.DEFAULT_MULTIPART_PART_SIZE = 8 * 1024 * 1024;
|
|
20
|
+
function positiveSafe(value, name) {
|
|
21
|
+
const n = Number(value);
|
|
22
|
+
if (!Number.isSafeInteger(n) || n <= 0)
|
|
23
|
+
throw new TypeError(`Invalid ${name}`);
|
|
24
|
+
return n;
|
|
25
|
+
}
|
|
26
|
+
function validateFile(file) {
|
|
27
|
+
if (!file || typeof file.name !== 'string' || !file.name || !Number.isSafeInteger(file.size) || file.size < 0 || typeof file.slice !== 'function')
|
|
28
|
+
throw new TypeError('A File is required');
|
|
29
|
+
}
|
|
30
|
+
/** All platform requests are scoped to this instance; storage requests never carry its API key. */
|
|
31
|
+
class FilesClient {
|
|
32
|
+
http;
|
|
33
|
+
api;
|
|
34
|
+
multipart;
|
|
35
|
+
constructor(http) {
|
|
36
|
+
this.http = http;
|
|
37
|
+
this.api = (0, api_generated_js_1.createOpenAPI)(http).assets.files;
|
|
38
|
+
this.multipart = this.api.multipart;
|
|
39
|
+
}
|
|
40
|
+
async storage(urlString, init, options = {}) {
|
|
41
|
+
const url = new URL(urlString);
|
|
42
|
+
if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password)
|
|
43
|
+
throw new TypeError('Invalid signed storage URL');
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
const abort = () => controller.abort(options.signal?.reason);
|
|
46
|
+
const timer = setTimeout(() => controller.abort(), this.http.timeoutMs);
|
|
47
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
48
|
+
try {
|
|
49
|
+
if (options.signal?.aborted)
|
|
50
|
+
abort();
|
|
51
|
+
const response = await this.http.getFetch()(url.href, { ...init, signal: controller.signal, credentials: 'omit', redirect: 'error' });
|
|
52
|
+
if (!response.ok)
|
|
53
|
+
throw new client_js_1.ApiError(response.status, 0, 'Object storage request failed');
|
|
54
|
+
return response;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
options.signal?.removeEventListener('abort', abort);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async upload(file, options = {}) {
|
|
62
|
+
validateFile(file);
|
|
63
|
+
if (file.size > exports.MULTIPART_THRESHOLD_BYTES)
|
|
64
|
+
return this.uploadMultipart(file, options);
|
|
65
|
+
const { signal, ...metadata } = options;
|
|
66
|
+
const prepared = await this.api.prepareUpload({ ...metadata, fileName: file.name, size: file.size, contentType: file.type || 'application/octet-stream' }, { signal });
|
|
67
|
+
if (!prepared.postUrl || !prepared.filePath || !prepared.postFields)
|
|
68
|
+
throw new client_js_1.ApiError(200, 0, 'Invalid upload preparation response');
|
|
69
|
+
const form = new FormData();
|
|
70
|
+
for (const [name, value] of Object.entries(prepared.postFields))
|
|
71
|
+
form.append(name, value);
|
|
72
|
+
form.append('file', file);
|
|
73
|
+
await this.storage(prepared.postUrl, { method: 'POST', body: form }, { signal });
|
|
74
|
+
return prepared;
|
|
75
|
+
}
|
|
76
|
+
async uploadMultipart(file, options = {}) {
|
|
77
|
+
validateFile(file);
|
|
78
|
+
if (file.size === 0)
|
|
79
|
+
throw new TypeError('Multipart upload requires a non-empty file');
|
|
80
|
+
const { signal, partSize = exports.DEFAULT_MULTIPART_PART_SIZE, onProgress, ...metadata } = options;
|
|
81
|
+
if (!Number.isSafeInteger(partSize) || partSize < 5 * 1024 * 1024)
|
|
82
|
+
throw new TypeError('partSize must be at least 5 MiB');
|
|
83
|
+
const start = await this.multipart.init({ ...metadata, fileName: file.name, contentType: file.type || 'application/octet-stream', size: file.size, partSize }, { signal });
|
|
84
|
+
const session = { fileKey: start.fileKey, uploadId: start.uploadId, parts: [], completionAttempted: false };
|
|
85
|
+
try {
|
|
86
|
+
const size = positiveSafe(start.partSize, 'server partSize');
|
|
87
|
+
const count = positiveSafe(start.partCount, 'server partCount');
|
|
88
|
+
if (!start.fileKey || !start.uploadId || count !== Math.ceil(file.size / size) || size < 5 * 1024 * 1024 || count > 10_000)
|
|
89
|
+
throw new TypeError('Invalid multipart preparation response');
|
|
90
|
+
for (let partNumber = 1; partNumber <= count; partNumber++) {
|
|
91
|
+
const result = await this.multipart.partUrls({ fileKey: start.fileKey, uploadId: start.uploadId, partNumbers: [partNumber] }, { signal });
|
|
92
|
+
const signed = result.partUrls.find(p => Number(p.partNumber) === partNumber);
|
|
93
|
+
if (!signed?.url)
|
|
94
|
+
throw new client_js_1.ApiError(200, 0, 'Missing signed part URL');
|
|
95
|
+
const end = Math.min(partNumber * size, file.size);
|
|
96
|
+
const response = await this.storage(signed.url, { method: 'PUT', body: file.slice((partNumber - 1) * size, end) }, { signal });
|
|
97
|
+
const etag = response.headers.get('etag');
|
|
98
|
+
if (!etag)
|
|
99
|
+
throw new client_js_1.ApiError(response.status, 0, 'Storage response is missing ETag');
|
|
100
|
+
session.parts.push({ partNumber, etag });
|
|
101
|
+
onProgress?.({ uploadedBytes: end, totalBytes: file.size });
|
|
102
|
+
}
|
|
103
|
+
session.completionAttempted = true;
|
|
104
|
+
return await this.multipart.complete({ fileKey: session.fileKey, uploadId: session.uploadId, parts: session.parts }, { signal });
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
throw new MultipartUploadError(session, error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
url(query, options) { return this.api.url(query, options); }
|
|
111
|
+
delete(body, options) { return this.api.delete(body, options); }
|
|
112
|
+
async download(query, options = {}) {
|
|
113
|
+
const { fileUrl } = await this.api.url(query, options);
|
|
114
|
+
return this.storage(fileUrl, { method: 'GET' }, options);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.FilesClient = FilesClient;
|
|
118
|
+
function createFilesClient(config = {}) { return new FilesClient(new client_js_1.HttpClient(config)); }
|
|
119
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/files.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpClient, ApiError, type ClientConfig, type RequestOptions } from './openapi/client.js';\nimport { createOpenAPI } from './openapi/api.generated.js';\nimport type { components } from './openapi/types.generated.js';\n\ntype Schemas = components['schemas'];\nexport type UploadOptions = Omit<Schemas['AssetFileUploadReq'], 'fileName' | 'contentType' | 'size'> & RequestOptions;\nexport type UploadResult = Schemas['AssetFileUploadResp'];\nexport type MultipartResult = Schemas['AssetFileMultipartCompleteResp'];\nexport interface MultipartOptions extends UploadOptions {\n partSize?: number;\n onProgress?: (progress: { uploadedBytes: number; totalBytes: number }) => void;\n}\nexport interface MultipartSession {\n fileKey: string;\n uploadId: string;\n parts: Schemas['AssetFileMultipartPart'][];\n completionAttempted: boolean;\n}\nexport class MultipartUploadError extends Error {\n constructor(readonly session: MultipartSession, readonly cause: unknown) {\n super('Multipart upload interrupted. The session is retained; reconcile completion before retrying or aborting.');\n this.name = 'MultipartUploadError';\n }\n}\nexport const MULTIPART_THRESHOLD_BYTES = 100 * 1024 * 1024;\nexport const DEFAULT_MULTIPART_PART_SIZE = 8 * 1024 * 1024;\n\nfunction positiveSafe(value: number | bigint, name: string): number {\n const n = Number(value);\n if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`Invalid ${name}`);\n return n;\n}\nfunction validateFile(file: File): void {\n if (!file || typeof file.name !== 'string' || !file.name || !Number.isSafeInteger(file.size) || file.size < 0 || typeof file.slice !== 'function') throw new TypeError('A File is required');\n}\n\n/** All platform requests are scoped to this instance; storage requests never carry its API key. */\nexport class FilesClient {\n private readonly api;\n readonly multipart;\n constructor(private readonly http: HttpClient) {\n this.api = createOpenAPI(http).assets.files;\n this.multipart = this.api.multipart;\n }\n\n private async storage(urlString: string, init: RequestInit, options: RequestOptions = {}): Promise<Response> {\n const url = new URL(urlString);\n if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password) throw new TypeError('Invalid signed storage URL');\n const controller = new AbortController();\n const abort = () => controller.abort(options.signal?.reason);\n const timer = setTimeout(() => controller.abort(), this.http.timeoutMs);\n options.signal?.addEventListener('abort', abort, { once: true });\n try {\n if (options.signal?.aborted) abort();\n const response = await this.http.getFetch()(url.href, { ...init, signal: controller.signal, credentials: 'omit', redirect: 'error' });\n if (!response.ok) throw new ApiError(response.status, 0, 'Object storage request failed');\n return response;\n } finally { clearTimeout(timer); options.signal?.removeEventListener('abort', abort); }\n }\n\n async upload(file: File, options: UploadOptions = {}): Promise<UploadResult | MultipartResult> {\n validateFile(file);\n if (file.size > MULTIPART_THRESHOLD_BYTES) return this.uploadMultipart(file, options);\n const { signal, ...metadata } = options;\n const prepared = await this.api.prepareUpload({ ...metadata, fileName: file.name, size: file.size, contentType: file.type || 'application/octet-stream' }, { signal });\n if (!prepared.postUrl || !prepared.filePath || !prepared.postFields) throw new ApiError(200, 0, 'Invalid upload preparation response');\n const form = new FormData();\n for (const [name, value] of Object.entries(prepared.postFields)) form.append(name, value);\n form.append('file', file);\n await this.storage(prepared.postUrl, { method: 'POST', body: form }, { signal });\n return prepared;\n }\n\n async uploadMultipart(file: File, options: MultipartOptions = {}): Promise<MultipartResult> {\n validateFile(file);\n if (file.size === 0) throw new TypeError('Multipart upload requires a non-empty file');\n const { signal, partSize = DEFAULT_MULTIPART_PART_SIZE, onProgress, ...metadata } = options;\n if (!Number.isSafeInteger(partSize) || partSize < 5 * 1024 * 1024) throw new TypeError('partSize must be at least 5 MiB');\n const start = await this.multipart.init({ ...metadata, fileName: file.name, contentType: file.type || 'application/octet-stream', size: file.size, partSize }, { signal });\n const session: MultipartSession = { fileKey: start.fileKey, uploadId: start.uploadId, parts: [], completionAttempted: false };\n try {\n const size = positiveSafe(start.partSize, 'server partSize');\n const count = positiveSafe(start.partCount, 'server partCount');\n if (!start.fileKey || !start.uploadId || count !== Math.ceil(file.size / size) || size < 5 * 1024 * 1024 || count > 10_000) throw new TypeError('Invalid multipart preparation response');\n for (let partNumber = 1; partNumber <= count; partNumber++) {\n const result = await this.multipart.partUrls({ fileKey: start.fileKey, uploadId: start.uploadId, partNumbers: [partNumber] }, { signal });\n const signed = result.partUrls.find(p => Number(p.partNumber) === partNumber);\n if (!signed?.url) throw new ApiError(200, 0, 'Missing signed part URL');\n const end = Math.min(partNumber * size, file.size);\n const response = await this.storage(signed.url, { method: 'PUT', body: file.slice((partNumber - 1) * size, end) }, { signal });\n const etag = response.headers.get('etag');\n if (!etag) throw new ApiError(response.status, 0, 'Storage response is missing ETag');\n session.parts.push({ partNumber, etag });\n onProgress?.({ uploadedBytes: end, totalBytes: file.size });\n }\n session.completionAttempted = true;\n return await this.multipart.complete({ fileKey: session.fileKey, uploadId: session.uploadId, parts: session.parts }, { signal });\n } catch (error) { throw new MultipartUploadError(session, error); }\n }\n\n url(query: Parameters<typeof this.api.url>[0], options?: RequestOptions) { return this.api.url(query, options); }\n delete(body: Schemas['AssetFileDeleteReq'], options?: RequestOptions) { return this.api.delete(body, options); }\n async download(query: Parameters<typeof this.api.url>[0], options: RequestOptions = {}): Promise<Response> {\n const { fileUrl } = await this.api.url(query, options);\n return this.storage(fileUrl, { method: 'GET' }, options);\n }\n}\nexport function createFilesClient(config: ClientConfig = {}): FilesClient { return new FilesClient(new HttpClient(config)); }\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function clientScope(client: object): number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clientScope = clientScope;
|
|
4
|
+
const scopes = new WeakMap();
|
|
5
|
+
let nextScope = 0;
|
|
6
|
+
function clientScope(client) {
|
|
7
|
+
let scope = scopes.get(client);
|
|
8
|
+
if (scope === undefined) {
|
|
9
|
+
scope = ++nextScope;
|
|
10
|
+
scopes.set(client, scope);
|
|
11
|
+
}
|
|
12
|
+
return scope;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=framework-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-scope.js","sourceRoot":"","sources":["../../src/framework-scope.ts"],"names":[],"mappings":";;AAEA,kCAIC;AAND,MAAM,MAAM,GAAG,IAAI,OAAO,EAAkB,CAAC;AAC7C,IAAI,SAAS,GAAG,CAAC,CAAC;AAClB,SAAgB,WAAW,CAAC,MAAc;IACxC,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAAC,KAAK,GAAG,EAAE,SAAS,CAAC;QAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAAC,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["const scopes = new WeakMap<object, number>();\nlet nextScope = 0;\nexport function clientScope(client: object): number {\n let scope = scopes.get(client);\n if (scope === undefined) { scope = ++nextScope; scopes.set(client, scope); }\n return scope;\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { createClient } from './client.js';
|
|
2
|
+
export type { Tier0Client, Tier0ClientConfig } from './client.js';
|
|
3
|
+
export { createSourceClient } from './source.js';
|
|
4
|
+
export type { SourceClient, SourceClientConfig } from './source.js';
|
|
5
|
+
export { createStreamClient } from './stream.js';
|
|
6
|
+
export type { StreamClient, StreamClientConfig } from './stream.js';
|
|
7
|
+
export { ApiError, TransportError, configureClient } from './openapi/client.js';
|
|
8
|
+
export type { ClientConfig, RequestOptions } from './openapi/client.js';
|
|
9
|
+
export type { components, paths } from './openapi/types.generated.js';
|
|
10
|
+
export * from './uns-v2/index.js';
|
|
11
|
+
export * from './controls.js';
|
|
12
|
+
export * from './capabilities.js';
|
|
13
|
+
export * from './files.js';
|
|
14
|
+
export * from './runtime-context.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.configureClient = exports.TransportError = exports.ApiError = exports.createStreamClient = exports.createSourceClient = exports.createClient = void 0;
|
|
18
|
+
var client_js_1 = require("./client.js");
|
|
19
|
+
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_js_1.createClient; } });
|
|
20
|
+
var source_js_1 = require("./source.js");
|
|
21
|
+
Object.defineProperty(exports, "createSourceClient", { enumerable: true, get: function () { return source_js_1.createSourceClient; } });
|
|
22
|
+
var stream_js_1 = require("./stream.js");
|
|
23
|
+
Object.defineProperty(exports, "createStreamClient", { enumerable: true, get: function () { return stream_js_1.createStreamClient; } });
|
|
24
|
+
var client_js_2 = require("./openapi/client.js");
|
|
25
|
+
Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return client_js_2.ApiError; } });
|
|
26
|
+
Object.defineProperty(exports, "TransportError", { enumerable: true, get: function () { return client_js_2.TransportError; } });
|
|
27
|
+
Object.defineProperty(exports, "configureClient", { enumerable: true, get: function () { return client_js_2.configureClient; } });
|
|
28
|
+
__exportStar(require("./uns-v2/index.js"), exports);
|
|
29
|
+
__exportStar(require("./controls.js"), exports);
|
|
30
|
+
__exportStar(require("./capabilities.js"), exports);
|
|
31
|
+
__exportStar(require("./files.js"), exports);
|
|
32
|
+
__exportStar(require("./runtime-context.js"), exports);
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yCAA2C;AAAlC,yGAAA,YAAY,OAAA;AAErB,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA;AAE3B,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA;AAE3B,iDAAgF;AAAvE,qGAAA,QAAQ,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,4GAAA,eAAe,OAAA;AAGlD,oDAAkC;AAClC,gDAA8B;AAC9B,oDAAkC;AAClC,6CAA2B;AAC3B,uDAAqC","sourcesContent":["export { createClient } from './client.js';\nexport type { Tier0Client, Tier0ClientConfig } from './client.js';\nexport { createSourceClient } from './source.js';\nexport type { SourceClient, SourceClientConfig } from './source.js';\nexport { createStreamClient } from './stream.js';\nexport type { StreamClient, StreamClientConfig } from './stream.js';\nexport { ApiError, TransportError, configureClient } from './openapi/client.js';\nexport type { ClientConfig, RequestOptions } from './openapi/client.js';\nexport type { components, paths } from './openapi/types.generated.js';\nexport * from './uns-v2/index.js';\nexport * from './controls.js';\nexport * from './capabilities.js';\nexport * from './files.js';\nexport * from './runtime-context.js';\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MQTT broker 地址归一化工具。
|
|
3
|
+
*
|
|
4
|
+
* 平台 `/openapi/v1/info` 返回的 `mqttBroker` 格式随环境变化,不保证统一:
|
|
5
|
+
* - enterprise:env 为空时后端兜底返回 `tcp://<host>:1883`(面向边缘/服务端客户端的连接串);
|
|
6
|
+
* - SaaS(Tier0 Cloud):env 原样透传,常见为 `host:port` 或裸 `host`。
|
|
7
|
+
*
|
|
8
|
+
* 浏览器 wss 客户端不应直接把它当 hostname 拼 URL(会得到 `wss://tcp://...`
|
|
9
|
+
* 这类非法地址),先经本模块解析/推导,再交给 `Tier0MQClient`。
|
|
10
|
+
*/
|
|
11
|
+
/** 解析后的 broker 端点。hostname 保证为裸主机(无 scheme、无端口、无路径)。 */
|
|
12
|
+
export interface MqttBrokerEndpoint {
|
|
13
|
+
/** 裸主机名(已剥离 scheme/path/query,不含端口)。 */
|
|
14
|
+
hostname: string;
|
|
15
|
+
/**
|
|
16
|
+
* 原始端口。注意:对 `tcp://host:1883` 这是 **tcp 端口**,浏览器 wss 场景
|
|
17
|
+
* 不能直接沿用(wss 通常是 8084),由 `toWebSocketUrl` 的 `wssPort` 决定。
|
|
18
|
+
*/
|
|
19
|
+
port?: number;
|
|
20
|
+
/** 原始 scheme(tcp/mqtt/mqtts/ws/wss/...),裸 host 输入时为 undefined。 */
|
|
21
|
+
scheme?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 解析各种形态的 broker 字符串为结构化端点。
|
|
25
|
+
*
|
|
26
|
+
* 兼容输入:`tcp://host:1883`、`mqtts://host:8883`、`wss://host:8084/mqtt`、
|
|
27
|
+
* `host:1883`、裸 `host`。无法解析(空串、非法 URL)返回 undefined。
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseMqttBroker(broker?: string | null): MqttBrokerEndpoint | undefined;
|
|
30
|
+
/** 浏览器 wss 默认端口(与平台 OS_MQTT_WEBSOCKET_TSL_PORT 默认值一致)。 */
|
|
31
|
+
export declare const DEFAULT_WSS_PORT = 8084;
|
|
32
|
+
/** MQTT over WebSocket 路径。 */
|
|
33
|
+
export declare const DEFAULT_WS_PATH = "/mqtt";
|
|
34
|
+
export interface ToWebSocketUrlOptions {
|
|
35
|
+
/** wss 端口,默认 {@link DEFAULT_WSS_PORT}(8084)。 */
|
|
36
|
+
wssPort?: number;
|
|
37
|
+
/**
|
|
38
|
+
* 显式指定 ws(false)/wss(true)。缺省自适应:浏览器 https 页面用 wss,
|
|
39
|
+
* 或 WebSocket 端口为 8084 时用 wss,其余用 ws。
|
|
40
|
+
*/
|
|
41
|
+
secure?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 当前运行环境是否处于 https 安全上下文。
|
|
45
|
+
*
|
|
46
|
+
* 用 `globalThis.location` 而不是 `window.location`:Web Worker
|
|
47
|
+
* (dedicated/shared)里 `window` 不存在,但 `location.protocol` 同样是 `https:`,
|
|
48
|
+
* 应同等视为安全上下文(否则会被降级为 ws 而被浏览器按 mixed content 拦截)。
|
|
49
|
+
*/
|
|
50
|
+
export declare function isBrowserHttps(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* 把 `mqttBroker`(或 {@link MqttBrokerEndpoint})推导为可直接传给
|
|
53
|
+
* `Tier0MQClient` 的 WebSocket URL。
|
|
54
|
+
*
|
|
55
|
+
* 规则:
|
|
56
|
+
* - 输入已是 `ws(s)://` URL:原样归一(补 `/mqtt` 路径,端口、path、query 均保留);
|
|
57
|
+
* - 输入 `tcp://host:1883` / `host:port` / 裸 `host`:按 `secure` 推导 scheme,
|
|
58
|
+
* 端口一律用 `wssPort`(8084),**不沿用** tcp 端口;
|
|
59
|
+
* - 输入为空/无法解析:返回 undefined(调用方应回退或报错,勿硬拼 URL)。
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* toWebSocketUrl('tcp://example.tier0.dev:1883', { secure: true });
|
|
63
|
+
* // → 'wss://example.tier0.dev:8084/mqtt'
|
|
64
|
+
*/
|
|
65
|
+
export declare function toWebSocketUrl(broker: string | MqttBrokerEndpoint | undefined | null, opts?: ToWebSocketUrlOptions): string | undefined;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MQTT broker 地址归一化工具。
|
|
4
|
+
*
|
|
5
|
+
* 平台 `/openapi/v1/info` 返回的 `mqttBroker` 格式随环境变化,不保证统一:
|
|
6
|
+
* - enterprise:env 为空时后端兜底返回 `tcp://<host>:1883`(面向边缘/服务端客户端的连接串);
|
|
7
|
+
* - SaaS(Tier0 Cloud):env 原样透传,常见为 `host:port` 或裸 `host`。
|
|
8
|
+
*
|
|
9
|
+
* 浏览器 wss 客户端不应直接把它当 hostname 拼 URL(会得到 `wss://tcp://...`
|
|
10
|
+
* 这类非法地址),先经本模块解析/推导,再交给 `Tier0MQClient`。
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.DEFAULT_WS_PATH = exports.DEFAULT_WSS_PORT = void 0;
|
|
14
|
+
exports.parseMqttBroker = parseMqttBroker;
|
|
15
|
+
exports.isBrowserHttps = isBrowserHttps;
|
|
16
|
+
exports.toWebSocketUrl = toWebSocketUrl;
|
|
17
|
+
const SCHEME_RE = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\//;
|
|
18
|
+
/**
|
|
19
|
+
* 解析各种形态的 broker 字符串为结构化端点。
|
|
20
|
+
*
|
|
21
|
+
* 兼容输入:`tcp://host:1883`、`mqtts://host:8883`、`wss://host:8084/mqtt`、
|
|
22
|
+
* `host:1883`、裸 `host`。无法解析(空串、非法 URL)返回 undefined。
|
|
23
|
+
*/
|
|
24
|
+
function parseMqttBroker(broker) {
|
|
25
|
+
const raw = broker?.trim();
|
|
26
|
+
if (!raw)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (SCHEME_RE.test(raw)) {
|
|
29
|
+
try {
|
|
30
|
+
const u = new URL(raw);
|
|
31
|
+
if (!u.hostname)
|
|
32
|
+
return undefined;
|
|
33
|
+
const scheme = SCHEME_RE.exec(raw)?.[1]?.toLowerCase();
|
|
34
|
+
return {
|
|
35
|
+
hostname: u.hostname,
|
|
36
|
+
port: u.port ? Number.parseInt(u.port, 10) : undefined,
|
|
37
|
+
scheme,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// 无 scheme:`host:port` 或裸 `host`;含路径/空白的是垃圾输入,拒绝
|
|
45
|
+
if (/[\s/]/.test(raw))
|
|
46
|
+
return undefined;
|
|
47
|
+
const i = raw.lastIndexOf(':');
|
|
48
|
+
if (i > 0 && /^\d+$/.test(raw.slice(i + 1))) {
|
|
49
|
+
const hostname = raw.slice(0, i);
|
|
50
|
+
if (!hostname)
|
|
51
|
+
return undefined;
|
|
52
|
+
return { hostname, port: Number.parseInt(raw.slice(i + 1), 10) };
|
|
53
|
+
}
|
|
54
|
+
return { hostname: raw };
|
|
55
|
+
}
|
|
56
|
+
/** 浏览器 wss 默认端口(与平台 OS_MQTT_WEBSOCKET_TSL_PORT 默认值一致)。 */
|
|
57
|
+
exports.DEFAULT_WSS_PORT = 8084;
|
|
58
|
+
/** MQTT over WebSocket 路径。 */
|
|
59
|
+
exports.DEFAULT_WS_PATH = '/mqtt';
|
|
60
|
+
/**
|
|
61
|
+
* 当前运行环境是否处于 https 安全上下文。
|
|
62
|
+
*
|
|
63
|
+
* 用 `globalThis.location` 而不是 `window.location`:Web Worker
|
|
64
|
+
* (dedicated/shared)里 `window` 不存在,但 `location.protocol` 同样是 `https:`,
|
|
65
|
+
* 应同等视为安全上下文(否则会被降级为 ws 而被浏览器按 mixed content 拦截)。
|
|
66
|
+
*/
|
|
67
|
+
function isBrowserHttps() {
|
|
68
|
+
const loc = globalThis.location;
|
|
69
|
+
return typeof loc?.protocol === 'string' && loc.protocol === 'https:';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 把 `mqttBroker`(或 {@link MqttBrokerEndpoint})推导为可直接传给
|
|
73
|
+
* `Tier0MQClient` 的 WebSocket URL。
|
|
74
|
+
*
|
|
75
|
+
* 规则:
|
|
76
|
+
* - 输入已是 `ws(s)://` URL:原样归一(补 `/mqtt` 路径,端口、path、query 均保留);
|
|
77
|
+
* - 输入 `tcp://host:1883` / `host:port` / 裸 `host`:按 `secure` 推导 scheme,
|
|
78
|
+
* 端口一律用 `wssPort`(8084),**不沿用** tcp 端口;
|
|
79
|
+
* - 输入为空/无法解析:返回 undefined(调用方应回退或报错,勿硬拼 URL)。
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* toWebSocketUrl('tcp://example.tier0.dev:1883', { secure: true });
|
|
83
|
+
* // → 'wss://example.tier0.dev:8084/mqtt'
|
|
84
|
+
*/
|
|
85
|
+
function toWebSocketUrl(broker, opts = {}) {
|
|
86
|
+
if (broker == null || broker === '')
|
|
87
|
+
return undefined;
|
|
88
|
+
// 已是 ws(s) URL:解析后归一直通(保留其 scheme/端口/path/query,仅补 /mqtt 路径)
|
|
89
|
+
if (typeof broker === 'string' && /^wss?:\/\//i.test(broker.trim())) {
|
|
90
|
+
try {
|
|
91
|
+
const u = new URL(broker.trim());
|
|
92
|
+
if (!u.hostname)
|
|
93
|
+
return undefined;
|
|
94
|
+
if (!u.pathname || u.pathname === '/') {
|
|
95
|
+
u.pathname = exports.DEFAULT_WS_PATH;
|
|
96
|
+
}
|
|
97
|
+
return u.toString();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const endpoint = typeof broker === 'string' ? parseMqttBroker(broker) : broker;
|
|
104
|
+
if (!endpoint?.hostname)
|
|
105
|
+
return undefined;
|
|
106
|
+
// ws(s) 端点:保留其 scheme 与端口("已是 WebSocket 地址"的直通语义)
|
|
107
|
+
if (endpoint.scheme === 'ws' || endpoint.scheme === 'wss') {
|
|
108
|
+
const port = endpoint.port ? `:${endpoint.port}` : '';
|
|
109
|
+
return `${endpoint.scheme}://${endpoint.hostname}${port}${exports.DEFAULT_WS_PATH}`;
|
|
110
|
+
}
|
|
111
|
+
const port = opts.wssPort ?? exports.DEFAULT_WSS_PORT;
|
|
112
|
+
const secure = opts.secure ?? (isBrowserHttps() || port === exports.DEFAULT_WSS_PORT);
|
|
113
|
+
return `${secure ? 'wss' : 'ws'}://${endpoint.hostname}:${port}${exports.DEFAULT_WS_PATH}`;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=broker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker.js","sourceRoot":"","sources":["../../../src/mq/broker.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAuBH,0CA4BC;AAwBD,wCAGC;AAgBD,wCAgCC;AA/GD,MAAM,SAAS,GAAG,iCAAiC,CAAC;AAEpD;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,MAAsB;IACpD,MAAM,GAAG,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAE3B,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,CAAC,CAAC,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAClC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;YACvD,OAAO;gBACL,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;gBACtD,MAAM;aACP,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAC;QAChC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACnE,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED,0DAA0D;AAC7C,QAAA,gBAAgB,GAAG,IAAI,CAAC;AACrC,8BAA8B;AACjB,QAAA,eAAe,GAAG,OAAO,CAAC;AAYvC;;;;;;GAMG;AACH,SAAgB,cAAc;IAC5B,MAAM,GAAG,GAAI,UAAmD,CAAC,QAAQ,CAAC;IAC1E,OAAO,OAAO,GAAG,EAAE,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,cAAc,CAC5B,MAAsD,EACtD,OAA8B,EAAE;IAEhC,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAEtD,6DAA6D;IAC7D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,CAAC,CAAC,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAClC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;gBACtC,CAAC,CAAC,QAAQ,GAAG,uBAAe,CAAC;YAC/B,CAAC;YACD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/E,IAAI,CAAC,QAAQ,EAAE,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE1C,kDAAkD;IAClD,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,OAAO,GAAG,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAAG,uBAAe,EAAE,CAAC;IAC9E,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,IAAI,wBAAgB,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,IAAI,IAAI,KAAK,wBAAgB,CAAC,CAAC;IAC9E,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,QAAQ,CAAC,QAAQ,IAAI,IAAI,GAAG,uBAAe,EAAE,CAAC;AACrF,CAAC","sourcesContent":["/**\n * MQTT broker 地址归一化工具。\n *\n * 平台 `/openapi/v1/info` 返回的 `mqttBroker` 格式随环境变化,不保证统一:\n * - enterprise:env 为空时后端兜底返回 `tcp://<host>:1883`(面向边缘/服务端客户端的连接串);\n * - SaaS(Tier0 Cloud):env 原样透传,常见为 `host:port` 或裸 `host`。\n *\n * 浏览器 wss 客户端不应直接把它当 hostname 拼 URL(会得到 `wss://tcp://...`\n * 这类非法地址),先经本模块解析/推导,再交给 `Tier0MQClient`。\n */\n\n/** 解析后的 broker 端点。hostname 保证为裸主机(无 scheme、无端口、无路径)。 */\nexport interface MqttBrokerEndpoint {\n /** 裸主机名(已剥离 scheme/path/query,不含端口)。 */\n hostname: string;\n /**\n * 原始端口。注意:对 `tcp://host:1883` 这是 **tcp 端口**,浏览器 wss 场景\n * 不能直接沿用(wss 通常是 8084),由 `toWebSocketUrl` 的 `wssPort` 决定。\n */\n port?: number;\n /** 原始 scheme(tcp/mqtt/mqtts/ws/wss/...),裸 host 输入时为 undefined。 */\n scheme?: string;\n}\n\nconst SCHEME_RE = /^([a-zA-Z][a-zA-Z0-9+.-]*):\\/\\//;\n\n/**\n * 解析各种形态的 broker 字符串为结构化端点。\n *\n * 兼容输入:`tcp://host:1883`、`mqtts://host:8883`、`wss://host:8084/mqtt`、\n * `host:1883`、裸 `host`。无法解析(空串、非法 URL)返回 undefined。\n */\nexport function parseMqttBroker(broker?: string | null): MqttBrokerEndpoint | undefined {\n const raw = broker?.trim();\n if (!raw) return undefined;\n\n if (SCHEME_RE.test(raw)) {\n try {\n const u = new URL(raw);\n if (!u.hostname) return undefined;\n const scheme = SCHEME_RE.exec(raw)?.[1]?.toLowerCase();\n return {\n hostname: u.hostname,\n port: u.port ? Number.parseInt(u.port, 10) : undefined,\n scheme,\n };\n } catch {\n return undefined;\n }\n }\n\n // 无 scheme:`host:port` 或裸 `host`;含路径/空白的是垃圾输入,拒绝\n if (/[\\s/]/.test(raw)) return undefined;\n const i = raw.lastIndexOf(':');\n if (i > 0 && /^\\d+$/.test(raw.slice(i + 1))) {\n const hostname = raw.slice(0, i);\n if (!hostname) return undefined;\n return { hostname, port: Number.parseInt(raw.slice(i + 1), 10) };\n }\n return { hostname: raw };\n}\n\n/** 浏览器 wss 默认端口(与平台 OS_MQTT_WEBSOCKET_TSL_PORT 默认值一致)。 */\nexport const DEFAULT_WSS_PORT = 8084;\n/** MQTT over WebSocket 路径。 */\nexport const DEFAULT_WS_PATH = '/mqtt';\n\nexport interface ToWebSocketUrlOptions {\n /** wss 端口,默认 {@link DEFAULT_WSS_PORT}(8084)。 */\n wssPort?: number;\n /**\n * 显式指定 ws(false)/wss(true)。缺省自适应:浏览器 https 页面用 wss,\n * 或 WebSocket 端口为 8084 时用 wss,其余用 ws。\n */\n secure?: boolean;\n}\n\n/**\n * 当前运行环境是否处于 https 安全上下文。\n *\n * 用 `globalThis.location` 而不是 `window.location`:Web Worker\n * (dedicated/shared)里 `window` 不存在,但 `location.protocol` 同样是 `https:`,\n * 应同等视为安全上下文(否则会被降级为 ws 而被浏览器按 mixed content 拦截)。\n */\nexport function isBrowserHttps(): boolean {\n const loc = (globalThis as { location?: { protocol?: string } }).location;\n return typeof loc?.protocol === 'string' && loc.protocol === 'https:';\n}\n\n/**\n * 把 `mqttBroker`(或 {@link MqttBrokerEndpoint})推导为可直接传给\n * `Tier0MQClient` 的 WebSocket URL。\n *\n * 规则:\n * - 输入已是 `ws(s)://` URL:原样归一(补 `/mqtt` 路径,端口、path、query 均保留);\n * - 输入 `tcp://host:1883` / `host:port` / 裸 `host`:按 `secure` 推导 scheme,\n * 端口一律用 `wssPort`(8084),**不沿用** tcp 端口;\n * - 输入为空/无法解析:返回 undefined(调用方应回退或报错,勿硬拼 URL)。\n *\n * @example\n * toWebSocketUrl('tcp://example.tier0.dev:1883', { secure: true });\n * // → 'wss://example.tier0.dev:8084/mqtt'\n */\nexport function toWebSocketUrl(\n broker: string | MqttBrokerEndpoint | undefined | null,\n opts: ToWebSocketUrlOptions = {},\n): string | undefined {\n if (broker == null || broker === '') return undefined;\n\n // 已是 ws(s) URL:解析后归一直通(保留其 scheme/端口/path/query,仅补 /mqtt 路径)\n if (typeof broker === 'string' && /^wss?:\\/\\//i.test(broker.trim())) {\n try {\n const u = new URL(broker.trim());\n if (!u.hostname) return undefined;\n if (!u.pathname || u.pathname === '/') {\n u.pathname = DEFAULT_WS_PATH;\n }\n return u.toString();\n } catch {\n return undefined;\n }\n }\n\n const endpoint = typeof broker === 'string' ? parseMqttBroker(broker) : broker;\n if (!endpoint?.hostname) return undefined;\n\n // ws(s) 端点:保留其 scheme 与端口(\"已是 WebSocket 地址\"的直通语义)\n if (endpoint.scheme === 'ws' || endpoint.scheme === 'wss') {\n const port = endpoint.port ? `:${endpoint.port}` : '';\n return `${endpoint.scheme}://${endpoint.hostname}${port}${DEFAULT_WS_PATH}`;\n }\n\n const port = opts.wssPort ?? DEFAULT_WSS_PORT;\n const secure = opts.secure ?? (isBrowserHttps() || port === DEFAULT_WSS_PORT);\n return `${secure ? 'wss' : 'ws'}://${endpoint.hostname}:${port}${DEFAULT_WS_PATH}`;\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { MQTTConfig, MQTTEventMap } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 消息回调。公开类型保持 `void` 返回,以兼容 async handler、`push()` 简写等
|
|
4
|
+
* 既有写法;运行时额外识别返回值:handler 返回严格的 `false` 视为下游停滞
|
|
5
|
+
* (背压),SDK 会统计连续背压次数,配合 MQTTConfig.maxBackpressuredDeliveries
|
|
6
|
+
* 可在阈值内自动移除订阅。
|
|
7
|
+
*/
|
|
8
|
+
export type TopicHandler = (topic: string, payload: string) => void;
|
|
9
|
+
export declare class Tier0MQClient {
|
|
10
|
+
private client;
|
|
11
|
+
private config;
|
|
12
|
+
private explicitClientId;
|
|
13
|
+
private explicitUsername;
|
|
14
|
+
private listeners;
|
|
15
|
+
private subscriptions;
|
|
16
|
+
private connectingPromise;
|
|
17
|
+
private _connected;
|
|
18
|
+
constructor(config?: MQTTConfig);
|
|
19
|
+
private get mqttUrl();
|
|
20
|
+
private ensureConnected;
|
|
21
|
+
private doConnect;
|
|
22
|
+
connect(config?: MQTTConfig): Promise<void>;
|
|
23
|
+
subscribe(topic: string, handler: TopicHandler): void;
|
|
24
|
+
unsubscribe(topic: string, handler?: TopicHandler): void;
|
|
25
|
+
publish(topic: string, payload: string | object, options?: {
|
|
26
|
+
qos?: number;
|
|
27
|
+
retain?: boolean;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
disconnect(): void;
|
|
30
|
+
on<K extends keyof MQTTEventMap>(event: K, handler: MQTTEventMap[K]): void;
|
|
31
|
+
off<K extends keyof MQTTEventMap>(event: K, handler: MQTTEventMap[K]): void;
|
|
32
|
+
private emit;
|
|
33
|
+
private resubscribeAll;
|
|
34
|
+
private topicMatch;
|
|
35
|
+
get isConnected(): boolean;
|
|
36
|
+
get subscribedTopics(): string[];
|
|
37
|
+
}
|