@ticketpm/core 0.0.4
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 +372 -0
- package/README.md +364 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/canonical.d.ts +26 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +51 -0
- package/dist/canonical.js.map +1 -0
- package/dist/compact.d.ts +24 -0
- package/dist/compact.d.ts.map +1 -0
- package/dist/compact.js +164 -0
- package/dist/compact.js.map +1 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +11 -0
- package/dist/constants.js.map +1 -0
- package/dist/identity.d.ts +24 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +35 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/media-proxy.d.ts +100 -0
- package/dist/media-proxy.d.ts.map +1 -0
- package/dist/media-proxy.js +318 -0
- package/dist/media-proxy.js.map +1 -0
- package/dist/runtime.d.ts +12 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +48 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +509 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +94 -0
- package/dist/types.js.map +1 -0
- package/dist/upload-client.d.ts +99 -0
- package/dist/upload-client.d.ts.map +1 -0
- package/dist/upload-client.js +115 -0
- package/dist/upload-client.js.map +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +35 -0
- package/dist/utils.js.map +1 -0
- package/dist/validation.d.ts +34 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +425 -0
- package/dist/validation.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { MAX_TRANSCRIPT_COMPRESSED_BYTES, MAX_TRANSCRIPT_DECOMPRESSED_BYTES } from "./constants.js";
|
|
2
|
+
import { TicketPmMediaProxyClient, type TicketPmMediaProxyClientOptions, type UploadProgressCallback } from "./media-proxy.js";
|
|
3
|
+
import type { StoredTranscript, TranscriptBuildInput } from "./types.js";
|
|
4
|
+
export interface TicketPmUploadClientOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Base transcript API URL, for example `https://ticket.pm/v2`.
|
|
7
|
+
*/
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
/**
|
|
10
|
+
* Optional bearer token or raw token string. Raw values are normalized into
|
|
11
|
+
* the `Authorization: Bearer ...` header automatically.
|
|
12
|
+
*/
|
|
13
|
+
token?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional custom fetch implementation for environments that need their own
|
|
16
|
+
* HTTP transport, instrumentation, retries, or authentication pipeline.
|
|
17
|
+
*/
|
|
18
|
+
fetch?: typeof fetch;
|
|
19
|
+
/**
|
|
20
|
+
* Base URL used when `uploadDraftTranscript()` auto-creates a media proxy
|
|
21
|
+
* client for you.
|
|
22
|
+
*
|
|
23
|
+
* Defaults to `https://m.ticket.pm/v2`.
|
|
24
|
+
*/
|
|
25
|
+
defaultMediaProxyBaseUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface UploadCompressedTranscriptOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Match the current first-party bot behavior of requesting URL-safe random IDs
|
|
30
|
+
* via `?uuid=uuid`.
|
|
31
|
+
*/
|
|
32
|
+
uuidStyleIds?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export type UploadDraftTranscriptMediaProxy = false | TicketPmMediaProxyClient | Partial<Pick<TicketPmMediaProxyClientOptions, "baseUrl" | "token" | "fetch">>;
|
|
35
|
+
export interface UploadDraftTranscriptOptions extends UploadCompressedTranscriptOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Optional ZSTD compression level forwarded to `compressStoredTranscript()`.
|
|
38
|
+
*/
|
|
39
|
+
level?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Media proxy configuration for draft uploads.
|
|
42
|
+
*
|
|
43
|
+
* - omit this value to auto-create a proxy client with the uploader token and
|
|
44
|
+
* `https://m.ticket.pm/v2`
|
|
45
|
+
* - pass an existing `TicketPmMediaProxyClient` to fully control media proxy
|
|
46
|
+
* behavior
|
|
47
|
+
* - pass a partial options object to override only `baseUrl`, `token`, and/or
|
|
48
|
+
* `fetch`
|
|
49
|
+
* - pass `false` to disable media proxying entirely for this upload
|
|
50
|
+
*/
|
|
51
|
+
mediaProxy?: UploadDraftTranscriptMediaProxy;
|
|
52
|
+
/**
|
|
53
|
+
* Optional progress callback for avatar cache uploads performed before the
|
|
54
|
+
* transcript is built.
|
|
55
|
+
*/
|
|
56
|
+
avatarProgress?: UploadProgressCallback;
|
|
57
|
+
/**
|
|
58
|
+
* Optional progress callback for attachment/embed/icon proxy rewrites
|
|
59
|
+
* performed before the transcript is built.
|
|
60
|
+
*/
|
|
61
|
+
mediaProgress?: UploadProgressCallback;
|
|
62
|
+
}
|
|
63
|
+
export interface TicketPmUploadResult {
|
|
64
|
+
id: string;
|
|
65
|
+
rateLimitRemaining?: number;
|
|
66
|
+
rateLimitReset?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Minimal upload client for `POST /v2/upload`.
|
|
70
|
+
*/
|
|
71
|
+
export declare class TicketPmUploadClient {
|
|
72
|
+
private readonly options;
|
|
73
|
+
private readonly fetchImpl;
|
|
74
|
+
constructor(options: TicketPmUploadClientOptions);
|
|
75
|
+
uploadCompressedTranscript(compressed: Uint8Array, options?: UploadCompressedTranscriptOptions): Promise<TicketPmUploadResult>;
|
|
76
|
+
uploadTranscript(transcript: StoredTranscript, options?: UploadCompressedTranscriptOptions & {
|
|
77
|
+
level?: number;
|
|
78
|
+
}): Promise<TicketPmUploadResult>;
|
|
79
|
+
/**
|
|
80
|
+
* High-level draft upload helper.
|
|
81
|
+
*
|
|
82
|
+
* This clones the draft transcript, proxies assets when enabled, compacts the
|
|
83
|
+
* draft into the stored transcript contract, compresses it, and uploads it.
|
|
84
|
+
*
|
|
85
|
+
* When `options.mediaProxy` is omitted, the client auto-creates a
|
|
86
|
+
* `TicketPmMediaProxyClient` using:
|
|
87
|
+
*
|
|
88
|
+
* - `baseUrl`: `options.defaultMediaProxyBaseUrl ?? https://m.ticket.pm/v2`
|
|
89
|
+
* - `token`: the uploader token
|
|
90
|
+
* - `fetch`: the uploader fetch implementation
|
|
91
|
+
*
|
|
92
|
+
* Pass `mediaProxy: false` to skip proxying and upload the original media
|
|
93
|
+
* fields unchanged.
|
|
94
|
+
*/
|
|
95
|
+
uploadDraftTranscript(draftTranscript: TranscriptBuildInput, options?: UploadDraftTranscriptOptions): Promise<TicketPmUploadResult>;
|
|
96
|
+
private resolveMediaProxyClient;
|
|
97
|
+
}
|
|
98
|
+
export { MAX_TRANSCRIPT_COMPRESSED_BYTES, MAX_TRANSCRIPT_DECOMPRESSED_BYTES };
|
|
99
|
+
//# sourceMappingURL=upload-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-client.d.ts","sourceRoot":"","sources":["../src/upload-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAEN,+BAA+B,EAC/B,iCAAiC,EACjC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEN,wBAAwB,EACxB,KAAK,+BAA+B,EACpC,KAAK,sBAAsB,EAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGzE,MAAM,WAAW,2BAA2B;IAC3C;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,iCAAiC;IACjD;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,+BAA+B,GACxC,KAAK,GACL,wBAAwB,GACxB,OAAO,CAAC,IAAI,CAAC,+BAA+B,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;AAEjF,MAAM,WAAW,4BAA6B,SAAQ,iCAAiC;IACtF;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,+BAA+B,CAAC;IAC7C;;;OAGG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC;;;OAGG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAUD;;GAEG;AACH,qBAAa,oBAAoB;IAGb,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEL,OAAO,EAAE,2BAA2B;IAI3D,0BAA0B,CACtC,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,iCAAiC,GACzC,OAAO,CAAC,oBAAoB,CAAC;IAgCnB,gBAAgB,CAC5B,UAAU,EAAE,gBAAgB,EAC5B,OAAO,CAAC,EAAE,iCAAiC,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC9D,OAAO,CAAC,oBAAoB,CAAC;IAOhC;;;;;;;;;;;;;;;OAeG;IACU,qBAAqB,CACjC,eAAe,EAAE,oBAAoB,EACrC,OAAO,CAAC,EAAE,4BAA4B,GACpC,OAAO,CAAC,oBAAoB,CAAC;IAehC,OAAO,CAAC,uBAAuB;CAe/B;AAuBD,OAAO,EAAE,+BAA+B,EAAE,iCAAiC,EAAE,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { compressStoredTranscript } from "./canonical.js";
|
|
2
|
+
import { buildStoredTranscript } from "./compact.js";
|
|
3
|
+
import { DEFAULT_TICKETPM_MEDIA_PROXY_BASE_URL, MAX_TRANSCRIPT_COMPRESSED_BYTES, MAX_TRANSCRIPT_DECOMPRESSED_BYTES } from "./constants.js";
|
|
4
|
+
import { proxyTranscriptAssetsInPlace, TicketPmMediaProxyClient } from "./media-proxy.js";
|
|
5
|
+
import { joinUrl } from "./utils.js";
|
|
6
|
+
function buildUploadHeaders(token) {
|
|
7
|
+
const headers = new Headers({ "Content-Type": "application/octet-stream" });
|
|
8
|
+
if (token) {
|
|
9
|
+
headers.set("Authorization", token.startsWith("Bearer ") ? token : `Bearer ${token}`);
|
|
10
|
+
}
|
|
11
|
+
return headers;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Minimal upload client for `POST /v2/upload`.
|
|
15
|
+
*/
|
|
16
|
+
export class TicketPmUploadClient {
|
|
17
|
+
options;
|
|
18
|
+
fetchImpl;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
22
|
+
}
|
|
23
|
+
async uploadCompressedTranscript(compressed, options) {
|
|
24
|
+
if (compressed.byteLength > MAX_TRANSCRIPT_COMPRESSED_BYTES) {
|
|
25
|
+
throw new Error(`Compressed transcript exceeds ${MAX_TRANSCRIPT_COMPRESSED_BYTES} bytes.`);
|
|
26
|
+
}
|
|
27
|
+
const uploadUrl = new URL(joinUrl(this.options.baseUrl, "/upload"));
|
|
28
|
+
if (options?.uuidStyleIds !== false) {
|
|
29
|
+
uploadUrl.searchParams.set("uuid", "uuid");
|
|
30
|
+
}
|
|
31
|
+
const response = await this.fetchImpl(uploadUrl, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: buildUploadHeaders(this.options.token),
|
|
34
|
+
body: Buffer.from(compressed)
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error(await response.text());
|
|
38
|
+
}
|
|
39
|
+
const payload = (await response.json());
|
|
40
|
+
if (typeof payload.id !== "string" || payload.id.length === 0) {
|
|
41
|
+
throw new Error("ticket.pm upload completed without returning a transcript id.");
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
id: payload.id,
|
|
45
|
+
rateLimitRemaining: readNumericHeader(response.headers, "X-RateLimit-Remaining"),
|
|
46
|
+
rateLimitReset: readNumericHeader(response.headers, "X-RateLimit-Reset")
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async uploadTranscript(transcript, options) {
|
|
50
|
+
const compressed = await compressStoredTranscript(transcript, {
|
|
51
|
+
level: options?.level
|
|
52
|
+
});
|
|
53
|
+
return this.uploadCompressedTranscript(compressed, options);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* High-level draft upload helper.
|
|
57
|
+
*
|
|
58
|
+
* This clones the draft transcript, proxies assets when enabled, compacts the
|
|
59
|
+
* draft into the stored transcript contract, compresses it, and uploads it.
|
|
60
|
+
*
|
|
61
|
+
* When `options.mediaProxy` is omitted, the client auto-creates a
|
|
62
|
+
* `TicketPmMediaProxyClient` using:
|
|
63
|
+
*
|
|
64
|
+
* - `baseUrl`: `options.defaultMediaProxyBaseUrl ?? https://m.ticket.pm/v2`
|
|
65
|
+
* - `token`: the uploader token
|
|
66
|
+
* - `fetch`: the uploader fetch implementation
|
|
67
|
+
*
|
|
68
|
+
* Pass `mediaProxy: false` to skip proxying and upload the original media
|
|
69
|
+
* fields unchanged.
|
|
70
|
+
*/
|
|
71
|
+
async uploadDraftTranscript(draftTranscript, options) {
|
|
72
|
+
const workingDraft = cloneTranscriptBuildInput(draftTranscript);
|
|
73
|
+
const mediaProxyClient = this.resolveMediaProxyClient(options?.mediaProxy);
|
|
74
|
+
if (mediaProxyClient) {
|
|
75
|
+
await proxyTranscriptAssetsInPlace(workingDraft, mediaProxyClient, {
|
|
76
|
+
avatarProgress: options?.avatarProgress,
|
|
77
|
+
mediaProgress: options?.mediaProgress
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const transcript = buildStoredTranscript(workingDraft);
|
|
81
|
+
return this.uploadTranscript(transcript, options);
|
|
82
|
+
}
|
|
83
|
+
resolveMediaProxyClient(mediaProxy) {
|
|
84
|
+
if (mediaProxy === false) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
if (mediaProxy instanceof TicketPmMediaProxyClient) {
|
|
88
|
+
return mediaProxy;
|
|
89
|
+
}
|
|
90
|
+
return new TicketPmMediaProxyClient({
|
|
91
|
+
baseUrl: mediaProxy?.baseUrl ?? this.options.defaultMediaProxyBaseUrl ?? DEFAULT_TICKETPM_MEDIA_PROXY_BASE_URL,
|
|
92
|
+
token: mediaProxy?.token ?? this.options.token,
|
|
93
|
+
fetch: mediaProxy?.fetch ?? this.fetchImpl
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function cloneTranscriptBuildInput(draftTranscript) {
|
|
98
|
+
if (typeof structuredClone === "function") {
|
|
99
|
+
return structuredClone(draftTranscript);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
context: JSON.parse(JSON.stringify(draftTranscript.context)),
|
|
103
|
+
messages: JSON.parse(JSON.stringify(draftTranscript.messages))
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function readNumericHeader(headers, key) {
|
|
107
|
+
const value = headers.get(key);
|
|
108
|
+
if (!value) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const parsed = Number(value);
|
|
112
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
113
|
+
}
|
|
114
|
+
export { MAX_TRANSCRIPT_COMPRESSED_BYTES, MAX_TRANSCRIPT_DECOMPRESSED_BYTES };
|
|
115
|
+
//# sourceMappingURL=upload-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-client.js","sourceRoot":"","sources":["../src/upload-client.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type UnknownRecord = Record<string, unknown>;
|
|
2
|
+
export declare function isRecord(value: unknown): value is UnknownRecord;
|
|
3
|
+
export declare function readTrimmedString(record: UnknownRecord, key: string): string | undefined;
|
|
4
|
+
export declare function sortRecordByKey<T>(record: Record<string, T> | undefined): Record<string, T> | undefined;
|
|
5
|
+
export declare function toUint8Array(value: Uint8Array | ArrayBuffer): Uint8Array;
|
|
6
|
+
export declare function joinUrl(baseUrl: string, path: string): string;
|
|
7
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQxF;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS,CAcvG;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,CAExE;AAGD,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7D"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function readTrimmedString(record, key) {
|
|
5
|
+
const value = record[key];
|
|
6
|
+
if (typeof value !== "string") {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const normalized = value.trim();
|
|
10
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
11
|
+
}
|
|
12
|
+
export function sortRecordByKey(record) {
|
|
13
|
+
if (!record) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return Object.keys(record)
|
|
17
|
+
.sort()
|
|
18
|
+
.reduce((accumulator, key) => {
|
|
19
|
+
const value = record[key];
|
|
20
|
+
if (value !== undefined) {
|
|
21
|
+
accumulator[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return accumulator;
|
|
24
|
+
}, {});
|
|
25
|
+
}
|
|
26
|
+
export function toUint8Array(value) {
|
|
27
|
+
return value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
28
|
+
}
|
|
29
|
+
// Ensure the endpoint joining works as intended without duping slashes
|
|
30
|
+
export function joinUrl(baseUrl, path) {
|
|
31
|
+
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
32
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
33
|
+
return `${normalizedBaseUrl}${normalizedPath}`;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAqB,EAAE,GAAW;IACnE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAChC,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,MAAqC;IACvE,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;SACxB,IAAI,EAAE;SACN,MAAM,CAAoB,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC1B,CAAC;QACD,OAAO,WAAW,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA+B;IAC3D,OAAO,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,IAAY;IACpD,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAChE,OAAO,GAAG,iBAAiB,GAAG,cAAc,EAAE,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StoredTranscript, UploadValidationResult } from "./types.js";
|
|
2
|
+
type UrlValidationResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
} | {
|
|
5
|
+
ok: false;
|
|
6
|
+
path: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Media URLs are tighter than regular links because the viewer renders them
|
|
12
|
+
* directly.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isValidMediaUrl(url: string | null | undefined): url is string;
|
|
15
|
+
/**
|
|
16
|
+
* Clickable links can point anywhere as long as the scheme is safe.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isValidLinkUrl(url: string | null | undefined): url is string;
|
|
19
|
+
/**
|
|
20
|
+
* Mirror the server-side URL walk so consumers can reject unsafe payloads
|
|
21
|
+
* before they reach `POST /v2/upload`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateTranscriptUrls(payload: unknown): UrlValidationResult;
|
|
24
|
+
/**
|
|
25
|
+
* Validate the same structural requirements enforced by the upload API itself.
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateTicketPmUploadPayload(transcript: unknown): UploadValidationResult;
|
|
28
|
+
/**
|
|
29
|
+
* Upload acceptance is looser than viewer rendering. This helper closes that
|
|
30
|
+
* gap by checking the compact hydration references that the renderer needs.
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateViewerCompatibility(transcript: StoredTranscript): UploadValidationResult;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAwB,gBAAgB,EAAyB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAMxH,KAAK,mBAAmB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AA0BpG;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,IAAI,MAAM,CAY7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,IAAI,MAAM,CAM5E;AAuSD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAwB5E;AAiCD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,OAAO,GAAG,sBAAsB,CAuBzF;AA4BD;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,gBAAgB,GAAG,sBAAsB,CAuDhG"}
|