@superblocksteam/shared 0.9567.3 → 0.9568.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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/socket/protocol.d.ts +13 -1
- package/dist/socket/protocol.d.ts.map +1 -1
- package/dist/socket/protocol.js.map +1 -1
- package/dist/types/ai/index.d.ts +43 -1
- package/dist/types/ai/index.d.ts.map +1 -1
- package/dist/types/ai/index.js +1 -1
- package/dist/types/ai/index.js.map +1 -1
- package/dist/types/ai/quota-paywall.d.ts +8 -1
- package/dist/types/ai/quota-paywall.d.ts.map +1 -1
- package/dist/types/ai/quota-paywall.js +46 -15
- package/dist/types/ai/quota-paywall.js.map +1 -1
- package/dist/types/billing/billing.d.ts +5 -0
- package/dist/types/billing/billing.d.ts.map +1 -1
- package/dist/types/billing/billing.js +3 -0
- package/dist/types/billing/billing.js.map +1 -1
- package/dist/types/fact/fact.d.ts +17 -0
- package/dist/types/fact/fact.d.ts.map +1 -1
- package/dist/types/rbac/index.d.ts +5 -0
- package/dist/types/rbac/index.d.ts.map +1 -1
- package/dist/types/rbac/index.js +5 -0
- package/dist/types/rbac/index.js.map +1 -1
- package/dist/utils/attachment-upload.d.ts +122 -0
- package/dist/utils/attachment-upload.d.ts.map +1 -0
- package/dist/utils/attachment-upload.js +356 -0
- package/dist/utils/attachment-upload.js.map +1 -0
- package/dist/utils/attachment-upload.test.d.ts +2 -0
- package/dist/utils/attachment-upload.test.d.ts.map +1 -0
- package/dist/utils/attachment-upload.test.js +126 -0
- package/dist/utils/attachment-upload.test.js.map +1 -0
- package/dist/utils/github-workflow.d.ts +6 -0
- package/dist/utils/github-workflow.d.ts.map +1 -0
- package/dist/utils/github-workflow.js +72 -0
- package/dist/utils/github-workflow.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist-esm/index.d.ts +1 -0
- package/dist-esm/index.d.ts.map +1 -1
- package/dist-esm/index.js +1 -0
- package/dist-esm/index.js.map +1 -1
- package/dist-esm/socket/protocol.d.ts +13 -1
- package/dist-esm/socket/protocol.d.ts.map +1 -1
- package/dist-esm/socket/protocol.js.map +1 -1
- package/dist-esm/types/ai/index.d.ts +43 -1
- package/dist-esm/types/ai/index.d.ts.map +1 -1
- package/dist-esm/types/ai/index.js +1 -1
- package/dist-esm/types/ai/index.js.map +1 -1
- package/dist-esm/types/ai/quota-paywall.d.ts +8 -1
- package/dist-esm/types/ai/quota-paywall.d.ts.map +1 -1
- package/dist-esm/types/ai/quota-paywall.js +45 -14
- package/dist-esm/types/ai/quota-paywall.js.map +1 -1
- package/dist-esm/types/billing/billing.d.ts +5 -0
- package/dist-esm/types/billing/billing.d.ts.map +1 -1
- package/dist-esm/types/billing/billing.js +3 -0
- package/dist-esm/types/billing/billing.js.map +1 -1
- package/dist-esm/types/fact/fact.d.ts +17 -0
- package/dist-esm/types/fact/fact.d.ts.map +1 -1
- package/dist-esm/types/rbac/index.d.ts +5 -0
- package/dist-esm/types/rbac/index.d.ts.map +1 -1
- package/dist-esm/types/rbac/index.js +5 -0
- package/dist-esm/types/rbac/index.js.map +1 -1
- package/dist-esm/utils/attachment-upload.d.ts +122 -0
- package/dist-esm/utils/attachment-upload.d.ts.map +1 -0
- package/dist-esm/utils/attachment-upload.js +345 -0
- package/dist-esm/utils/attachment-upload.js.map +1 -0
- package/dist-esm/utils/attachment-upload.test.d.ts +2 -0
- package/dist-esm/utils/attachment-upload.test.d.ts.map +1 -0
- package/dist-esm/utils/attachment-upload.test.js +124 -0
- package/dist-esm/utils/attachment-upload.test.js.map +1 -0
- package/dist-esm/utils/github-workflow.d.ts +6 -0
- package/dist-esm/utils/github-workflow.d.ts.map +1 -0
- package/dist-esm/utils/github-workflow.js +65 -0
- package/dist-esm/utils/github-workflow.js.map +1 -0
- package/dist-esm/utils/index.d.ts +1 -0
- package/dist-esm/utils/index.d.ts.map +1 -1
- package/dist-esm/utils/index.js +1 -0
- package/dist-esm/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/socket/protocol.ts +21 -1
- package/src/types/ai/index.ts +47 -1
- package/src/types/ai/quota-paywall.ts +53 -15
- package/src/types/billing/billing.ts +5 -0
- package/src/types/fact/fact.ts +18 -0
- package/src/types/rbac/index.ts +5 -0
- package/src/utils/attachment-upload.test.ts +153 -0
- package/src/utils/attachment-upload.ts +546 -0
- package/src/utils/github-workflow.ts +68 -0
- package/src/utils/index.ts +1 -0
- package/dist/types/ai/credit-pricing.d.ts +0 -47
- package/dist/types/ai/credit-pricing.d.ts.map +0 -1
- package/dist/types/ai/credit-pricing.js +0 -66
- package/dist/types/ai/credit-pricing.js.map +0 -1
- package/dist-esm/types/ai/credit-pricing.d.ts +0 -47
- package/dist-esm/types/ai/credit-pricing.d.ts.map +0 -1
- package/dist-esm/types/ai/credit-pricing.js +0 -61
- package/dist-esm/types/ai/credit-pricing.js.map +0 -1
- package/src/types/ai/credit-pricing.ts +0 -87
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
const DEFAULT_MIME_TYPE = 'application/octet-stream';
|
|
2
|
+
|
|
3
|
+
const TEXT_ATTACHMENT_MIME_TYPES = {
|
|
4
|
+
csv: 'text/csv',
|
|
5
|
+
css: 'text/css',
|
|
6
|
+
json: 'application/json',
|
|
7
|
+
txt: 'text/plain',
|
|
8
|
+
yaml: 'text/yaml'
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export const TEXT_LIKE_FILE_EXTENSIONS = [
|
|
12
|
+
'.txt',
|
|
13
|
+
'.text',
|
|
14
|
+
'.log',
|
|
15
|
+
'.md',
|
|
16
|
+
'.markdown',
|
|
17
|
+
'.csv',
|
|
18
|
+
'.tsv',
|
|
19
|
+
'.json',
|
|
20
|
+
'.jsonl',
|
|
21
|
+
'.ndjson',
|
|
22
|
+
'.xml',
|
|
23
|
+
'.yaml',
|
|
24
|
+
'.yml',
|
|
25
|
+
'.toml',
|
|
26
|
+
'.ini',
|
|
27
|
+
'.cfg',
|
|
28
|
+
'.conf',
|
|
29
|
+
'.env',
|
|
30
|
+
'.sh',
|
|
31
|
+
'.bash',
|
|
32
|
+
'.zsh',
|
|
33
|
+
'.js',
|
|
34
|
+
'.jsx',
|
|
35
|
+
'.ts',
|
|
36
|
+
'.tsx',
|
|
37
|
+
'.mts',
|
|
38
|
+
'.cts',
|
|
39
|
+
'.py',
|
|
40
|
+
'.go',
|
|
41
|
+
'.java',
|
|
42
|
+
'.rb',
|
|
43
|
+
'.php',
|
|
44
|
+
'.sql',
|
|
45
|
+
'.css',
|
|
46
|
+
'.scss',
|
|
47
|
+
'.html',
|
|
48
|
+
'.htm'
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
const MIME_TYPE_FILE_EXTENSIONS: Record<string, string> = {
|
|
52
|
+
'application/json': '.json',
|
|
53
|
+
'application/pdf': '.pdf',
|
|
54
|
+
'application/x-yaml': '.yaml',
|
|
55
|
+
'application/yaml': '.yaml',
|
|
56
|
+
'image/gif': '.gif',
|
|
57
|
+
'image/jpeg': '.jpg',
|
|
58
|
+
'image/jpg': '.jpg',
|
|
59
|
+
'image/png': '.png',
|
|
60
|
+
'image/webp': '.webp',
|
|
61
|
+
'text/css': '.css',
|
|
62
|
+
'text/csv': '.csv',
|
|
63
|
+
'text/plain': '.txt',
|
|
64
|
+
'text/yaml': '.yaml'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type UploadAttachmentDataLike = {
|
|
68
|
+
data: string;
|
|
69
|
+
mimeType?: string | null;
|
|
70
|
+
name?: string;
|
|
71
|
+
fileName?: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type UploadImageAttachmentLike = {
|
|
75
|
+
type: 'image';
|
|
76
|
+
image: string;
|
|
77
|
+
fileName: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
type UploadPdfAttachmentLike = {
|
|
81
|
+
type: 'pdf';
|
|
82
|
+
data: string;
|
|
83
|
+
fileName: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
type UploadTextAttachmentLike = {
|
|
87
|
+
type: 'csv' | 'css' | 'json' | 'txt' | 'yaml';
|
|
88
|
+
content: string;
|
|
89
|
+
fileName: string;
|
|
90
|
+
mimeType?: string | null;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type UploadUnsupportedAttachmentLike = {
|
|
94
|
+
type: 'uploaded';
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export type AttachmentUploadSourceLike =
|
|
98
|
+
| Blob
|
|
99
|
+
| File
|
|
100
|
+
| UploadAttachmentDataLike
|
|
101
|
+
| UploadImageAttachmentLike
|
|
102
|
+
| UploadPdfAttachmentLike
|
|
103
|
+
| UploadTextAttachmentLike
|
|
104
|
+
| UploadUnsupportedAttachmentLike;
|
|
105
|
+
|
|
106
|
+
export interface AttachmentUploadDescriptor {
|
|
107
|
+
blob: Blob;
|
|
108
|
+
fileName: string;
|
|
109
|
+
mimeType: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type AttachmentUploadScopeType = 'app' | 'org';
|
|
113
|
+
export type AttachmentUploadPurpose = 'attachment' | 'context';
|
|
114
|
+
|
|
115
|
+
export interface AppContextUploadDto {
|
|
116
|
+
applicationId: string;
|
|
117
|
+
branchName?: string;
|
|
118
|
+
commitId?: string;
|
|
119
|
+
purpose: 'context';
|
|
120
|
+
scopeType: 'app';
|
|
121
|
+
uploaded: true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface AttachmentUploadDto {
|
|
125
|
+
applicationId?: string;
|
|
126
|
+
attachmentId: string;
|
|
127
|
+
contentUrl: string;
|
|
128
|
+
fileName: string;
|
|
129
|
+
mimeType: string | null;
|
|
130
|
+
purpose: AttachmentUploadPurpose;
|
|
131
|
+
scopeType: AttachmentUploadScopeType;
|
|
132
|
+
signedUrl: string;
|
|
133
|
+
signedUrlExpiresAt: string;
|
|
134
|
+
storageKey: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type UploadBodyDto = AppContextUploadDto | AttachmentUploadDto;
|
|
138
|
+
|
|
139
|
+
// Backwards-compatible alias for existing attachment-only client consumers.
|
|
140
|
+
export type AttachmentUploadServerDto = AttachmentUploadDto;
|
|
141
|
+
|
|
142
|
+
export interface UploadedAttachmentLike {
|
|
143
|
+
type: 'uploaded';
|
|
144
|
+
url: string;
|
|
145
|
+
signedUrl: string;
|
|
146
|
+
mediaType: string;
|
|
147
|
+
fileName: string;
|
|
148
|
+
label?: string;
|
|
149
|
+
insight?: string;
|
|
150
|
+
storageKey?: string;
|
|
151
|
+
signedUrlExpiresAt: string;
|
|
152
|
+
scopeType?: AttachmentUploadScopeType;
|
|
153
|
+
applicationId?: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface AttachmentUploadMetadata {
|
|
157
|
+
label?: string;
|
|
158
|
+
insight?: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function buildAttachmentUploadMetadata(params: AttachmentUploadMetadata): AttachmentUploadMetadata | undefined {
|
|
162
|
+
const label = normalizeNonEmptyString(params.label);
|
|
163
|
+
const insight = normalizeNonEmptyString(params.insight);
|
|
164
|
+
|
|
165
|
+
if (!label && !insight) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
...(label ? { label } : {}),
|
|
171
|
+
...(insight ? { insight } : {})
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function normalizeNonEmptyString(value: unknown): string | undefined {
|
|
176
|
+
if (typeof value !== 'string') {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const trimmed = value.trim();
|
|
181
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function isTextLikeMimeType(mimeType: string): boolean {
|
|
185
|
+
const normalizedMimeType = mimeType.toLowerCase();
|
|
186
|
+
return (
|
|
187
|
+
normalizedMimeType.startsWith('text/') ||
|
|
188
|
+
normalizedMimeType.includes('json') ||
|
|
189
|
+
normalizedMimeType.includes('xml') ||
|
|
190
|
+
normalizedMimeType.includes('yaml') ||
|
|
191
|
+
normalizedMimeType.includes('toml') ||
|
|
192
|
+
normalizedMimeType.includes('javascript') ||
|
|
193
|
+
normalizedMimeType.includes('typescript') ||
|
|
194
|
+
normalizedMimeType.includes('ecmascript') ||
|
|
195
|
+
normalizedMimeType.includes('markdown') ||
|
|
196
|
+
normalizedMimeType.includes('shellscript') ||
|
|
197
|
+
normalizedMimeType.includes('python') ||
|
|
198
|
+
normalizedMimeType.includes('ruby') ||
|
|
199
|
+
normalizedMimeType.includes('php') ||
|
|
200
|
+
normalizedMimeType.includes('sql')
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function getTextAttachmentType(params: {
|
|
205
|
+
fileName?: string;
|
|
206
|
+
mimeType?: string | null;
|
|
207
|
+
}): 'csv' | 'css' | 'json' | 'txt' | 'yaml' | null {
|
|
208
|
+
const normalizedFileName = normalizeNonEmptyString(params.fileName)?.toLowerCase();
|
|
209
|
+
const normalizedMimeType = normalizeNonEmptyString(params.mimeType)?.toLowerCase();
|
|
210
|
+
|
|
211
|
+
if (normalizedMimeType === 'text/csv' || normalizedFileName?.endsWith('.csv')) {
|
|
212
|
+
return 'csv';
|
|
213
|
+
}
|
|
214
|
+
if (normalizedMimeType === 'application/json' || normalizedFileName?.endsWith('.json')) {
|
|
215
|
+
return 'json';
|
|
216
|
+
}
|
|
217
|
+
if (
|
|
218
|
+
normalizedMimeType === 'text/yaml' ||
|
|
219
|
+
normalizedMimeType === 'application/x-yaml' ||
|
|
220
|
+
normalizedMimeType === 'application/yaml' ||
|
|
221
|
+
normalizedFileName?.endsWith('.yaml') ||
|
|
222
|
+
normalizedFileName?.endsWith('.yml')
|
|
223
|
+
) {
|
|
224
|
+
return 'yaml';
|
|
225
|
+
}
|
|
226
|
+
if (normalizedMimeType === 'text/css' || normalizedFileName?.endsWith('.css')) {
|
|
227
|
+
return 'css';
|
|
228
|
+
}
|
|
229
|
+
if (
|
|
230
|
+
normalizedMimeType === 'text/plain' ||
|
|
231
|
+
(normalizedMimeType ? isTextLikeMimeType(normalizedMimeType) : false) ||
|
|
232
|
+
(normalizedFileName ? TEXT_LIKE_FILE_EXTENSIONS.some((extension) => normalizedFileName.endsWith(extension)) : false)
|
|
233
|
+
) {
|
|
234
|
+
return 'txt';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function getTextLikeMimeTypeFromFileName(fileName: string | undefined): string | undefined {
|
|
241
|
+
const textAttachmentType = getTextAttachmentType({ fileName });
|
|
242
|
+
return textAttachmentType ? TEXT_ATTACHMENT_MIME_TYPES[textAttachmentType] : undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function normalizeAttachmentMimeType(params: {
|
|
246
|
+
fileName?: string;
|
|
247
|
+
mimeType?: string | null;
|
|
248
|
+
fallbackMimeType?: string | null;
|
|
249
|
+
}): string {
|
|
250
|
+
const normalizedMimeType =
|
|
251
|
+
normalizeNonEmptyString(params.mimeType)?.toLowerCase() ?? normalizeNonEmptyString(params.fallbackMimeType)?.toLowerCase();
|
|
252
|
+
const textLikeMimeType = getTextLikeMimeTypeFromFileName(params.fileName);
|
|
253
|
+
|
|
254
|
+
if (!textLikeMimeType) {
|
|
255
|
+
return normalizedMimeType ?? DEFAULT_MIME_TYPE;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!normalizedMimeType) {
|
|
259
|
+
return textLikeMimeType;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return isTextLikeMimeType(normalizedMimeType) ? normalizedMimeType : textLikeMimeType;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getDefaultFileName(mimeType: string): string {
|
|
266
|
+
const normalizedMimeType = mimeType.toLowerCase();
|
|
267
|
+
const knownExtension = MIME_TYPE_FILE_EXTENSIONS[normalizedMimeType];
|
|
268
|
+
if (knownExtension) {
|
|
269
|
+
return `attachment${knownExtension}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (normalizedMimeType.startsWith('image/')) {
|
|
273
|
+
const subtype = normalizedMimeType.slice('image/'.length).split(/[+;]/)[0]?.trim();
|
|
274
|
+
if (subtype) {
|
|
275
|
+
return `attachment.${subtype}`;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return 'attachment';
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function resolveFileName(params: { fileName: unknown; fallbackFileName?: string; mimeType: string }): string {
|
|
283
|
+
return (
|
|
284
|
+
normalizeNonEmptyString(params.fileName) ?? normalizeNonEmptyString(params.fallbackFileName) ?? getDefaultFileName(params.mimeType)
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function decodeBase64(base64Data: string): Uint8Array {
|
|
289
|
+
return Uint8Array.from(atob(base64Data), (char) => char.charCodeAt(0));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function parseDataUrl(data: string): { base64Data: string; mimeType?: string } | null {
|
|
293
|
+
const match = data.match(/^data:([^;,]+)?(?:;base64)?,(.*)$/s);
|
|
294
|
+
if (!match) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
mimeType: normalizeNonEmptyString(match[1]),
|
|
300
|
+
base64Data: match[2] ?? ''
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function isAttachmentDataLike(source: AttachmentUploadSourceLike): source is UploadAttachmentDataLike {
|
|
305
|
+
return 'data' in source && typeof source.data === 'string' && !('type' in source);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function toAttachmentUploadDescriptor(
|
|
309
|
+
source: AttachmentUploadSourceLike,
|
|
310
|
+
options?: {
|
|
311
|
+
fallbackFileName?: string;
|
|
312
|
+
fallbackMimeType?: string;
|
|
313
|
+
}
|
|
314
|
+
): AttachmentUploadDescriptor | null {
|
|
315
|
+
if (source instanceof File) {
|
|
316
|
+
const mimeType = normalizeAttachmentMimeType({
|
|
317
|
+
fileName: source.name,
|
|
318
|
+
mimeType: source.type,
|
|
319
|
+
fallbackMimeType: options?.fallbackMimeType
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
blob: source,
|
|
324
|
+
fileName: resolveFileName({
|
|
325
|
+
fileName: source.name,
|
|
326
|
+
fallbackFileName: options?.fallbackFileName,
|
|
327
|
+
mimeType
|
|
328
|
+
}),
|
|
329
|
+
mimeType
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (source instanceof Blob) {
|
|
334
|
+
const sourceWithOptionalName = source as Blob & { name?: unknown };
|
|
335
|
+
const mimeType = normalizeAttachmentMimeType({
|
|
336
|
+
fileName: typeof sourceWithOptionalName.name === 'string' ? sourceWithOptionalName.name : options?.fallbackFileName,
|
|
337
|
+
mimeType: source.type,
|
|
338
|
+
fallbackMimeType: options?.fallbackMimeType
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
blob: source,
|
|
343
|
+
fileName: resolveFileName({
|
|
344
|
+
fileName: sourceWithOptionalName.name,
|
|
345
|
+
fallbackFileName: options?.fallbackFileName,
|
|
346
|
+
mimeType
|
|
347
|
+
}),
|
|
348
|
+
mimeType
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (isAttachmentDataLike(source)) {
|
|
353
|
+
const parsedDataUrl = parseDataUrl(source.data);
|
|
354
|
+
const mimeType = normalizeAttachmentMimeType({
|
|
355
|
+
fileName: typeof source.name === 'string' ? source.name : source.fileName,
|
|
356
|
+
mimeType: parsedDataUrl?.mimeType ?? source.mimeType,
|
|
357
|
+
fallbackMimeType: options?.fallbackMimeType
|
|
358
|
+
});
|
|
359
|
+
const base64Data = parsedDataUrl?.base64Data ?? source.data;
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
blob: new Blob([decodeBase64(base64Data)], { type: mimeType }),
|
|
363
|
+
fileName: resolveFileName({
|
|
364
|
+
fileName: source.name ?? source.fileName,
|
|
365
|
+
fallbackFileName: options?.fallbackFileName,
|
|
366
|
+
mimeType
|
|
367
|
+
}),
|
|
368
|
+
mimeType
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (source.type === 'image') {
|
|
373
|
+
const parsedDataUrl = parseDataUrl(source.image);
|
|
374
|
+
if (!parsedDataUrl?.mimeType) {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
blob: new Blob([decodeBase64(parsedDataUrl.base64Data)], {
|
|
380
|
+
type: parsedDataUrl.mimeType
|
|
381
|
+
}),
|
|
382
|
+
fileName: resolveFileName({
|
|
383
|
+
fileName: source.fileName,
|
|
384
|
+
fallbackFileName: options?.fallbackFileName,
|
|
385
|
+
mimeType: parsedDataUrl.mimeType
|
|
386
|
+
}),
|
|
387
|
+
mimeType: parsedDataUrl.mimeType
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (source.type === 'pdf') {
|
|
392
|
+
const parsedDataUrl = parseDataUrl(source.data);
|
|
393
|
+
const mimeType = parsedDataUrl?.mimeType ?? normalizeNonEmptyString(options?.fallbackMimeType) ?? 'application/pdf';
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
blob: new Blob([decodeBase64(parsedDataUrl?.base64Data ?? source.data)], {
|
|
397
|
+
type: mimeType
|
|
398
|
+
}),
|
|
399
|
+
fileName: resolveFileName({
|
|
400
|
+
fileName: source.fileName,
|
|
401
|
+
fallbackFileName: options?.fallbackFileName,
|
|
402
|
+
mimeType
|
|
403
|
+
}),
|
|
404
|
+
mimeType
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (source.type === 'csv' || source.type === 'css' || source.type === 'json' || source.type === 'txt' || source.type === 'yaml') {
|
|
409
|
+
const mimeType = normalizeAttachmentMimeType({
|
|
410
|
+
fileName: source.fileName,
|
|
411
|
+
mimeType: source.mimeType,
|
|
412
|
+
fallbackMimeType: options?.fallbackMimeType ?? TEXT_ATTACHMENT_MIME_TYPES[source.type]
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
return {
|
|
416
|
+
blob: new Blob([source.content], { type: mimeType }),
|
|
417
|
+
fileName: resolveFileName({
|
|
418
|
+
fileName: source.fileName,
|
|
419
|
+
fallbackFileName: options?.fallbackFileName,
|
|
420
|
+
mimeType
|
|
421
|
+
}),
|
|
422
|
+
mimeType
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export function buildAttachmentUploadFormData(params: {
|
|
430
|
+
descriptor: AttachmentUploadDescriptor;
|
|
431
|
+
prefix: string;
|
|
432
|
+
fieldName?: string;
|
|
433
|
+
branchId?: string;
|
|
434
|
+
commitId?: string;
|
|
435
|
+
metadata?: AttachmentUploadMetadata;
|
|
436
|
+
}): FormData {
|
|
437
|
+
const formData = new FormData();
|
|
438
|
+
formData.append(params.fieldName ?? 'file', params.descriptor.blob, params.descriptor.fileName);
|
|
439
|
+
formData.append('prefix', params.prefix);
|
|
440
|
+
|
|
441
|
+
if (params.branchId) {
|
|
442
|
+
formData.append('branchId', params.branchId);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (params.commitId) {
|
|
446
|
+
formData.append('commitId', params.commitId);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const metadata = buildAttachmentUploadMetadata(params.metadata ?? {});
|
|
450
|
+
if (metadata) {
|
|
451
|
+
formData.append('metadata', JSON.stringify(metadata));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return formData;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function createUploadedAttachmentFromServer(params: {
|
|
458
|
+
response: AttachmentUploadServerDto;
|
|
459
|
+
fallbackFileName: string;
|
|
460
|
+
fallbackMimeType: string;
|
|
461
|
+
label?: string;
|
|
462
|
+
insight?: string;
|
|
463
|
+
}): UploadedAttachmentLike {
|
|
464
|
+
const mediaType = normalizeNonEmptyString(params.response.mimeType) ?? params.fallbackMimeType;
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
type: 'uploaded',
|
|
468
|
+
url: normalizeNonEmptyString(params.response.contentUrl) ?? params.response.signedUrl,
|
|
469
|
+
signedUrl: params.response.signedUrl,
|
|
470
|
+
mediaType,
|
|
471
|
+
fileName: normalizeNonEmptyString(params.response.fileName) ?? params.fallbackFileName,
|
|
472
|
+
label: params.label,
|
|
473
|
+
insight: params.insight,
|
|
474
|
+
storageKey: normalizeNonEmptyString(params.response.storageKey),
|
|
475
|
+
signedUrlExpiresAt: params.response.signedUrlExpiresAt,
|
|
476
|
+
scopeType: params.response.scopeType,
|
|
477
|
+
applicationId: normalizeNonEmptyString(params.response.applicationId)
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Shared transport for POST /api/v1/files/upload. Builds form-data, URL with query params,
|
|
483
|
+
* fetches, and returns the raw server DTO. Callers map to their own types (e.g. Attachment,
|
|
484
|
+
* AttachmentUploadResult).
|
|
485
|
+
*/
|
|
486
|
+
export async function uploadAttachmentToServerApi(params: {
|
|
487
|
+
baseUrl: string;
|
|
488
|
+
authorization: string;
|
|
489
|
+
descriptor: AttachmentUploadDescriptor;
|
|
490
|
+
scopeType: AttachmentUploadScopeType;
|
|
491
|
+
purpose: AttachmentUploadPurpose;
|
|
492
|
+
applicationId?: string;
|
|
493
|
+
branchName?: string;
|
|
494
|
+
commitId?: string;
|
|
495
|
+
prefix?: string;
|
|
496
|
+
metadata?: AttachmentUploadMetadata;
|
|
497
|
+
}): Promise<AttachmentUploadServerDto> {
|
|
498
|
+
const {
|
|
499
|
+
baseUrl,
|
|
500
|
+
authorization,
|
|
501
|
+
descriptor,
|
|
502
|
+
scopeType,
|
|
503
|
+
purpose,
|
|
504
|
+
applicationId,
|
|
505
|
+
branchName,
|
|
506
|
+
commitId,
|
|
507
|
+
prefix = 'message-attachment',
|
|
508
|
+
metadata
|
|
509
|
+
} = params;
|
|
510
|
+
|
|
511
|
+
const formData = buildAttachmentUploadFormData({
|
|
512
|
+
descriptor,
|
|
513
|
+
prefix,
|
|
514
|
+
metadata,
|
|
515
|
+
...(branchName != null && { branchId: branchName }),
|
|
516
|
+
...(commitId != null && { commitId })
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
const uploadUrl = new URL('/api/v1/files/upload', baseUrl);
|
|
520
|
+
uploadUrl.searchParams.set('scopeType', scopeType);
|
|
521
|
+
uploadUrl.searchParams.set('purpose', purpose);
|
|
522
|
+
if (applicationId != null && applicationId.trim() !== '') {
|
|
523
|
+
uploadUrl.searchParams.set('applicationId', applicationId);
|
|
524
|
+
}
|
|
525
|
+
if (branchName != null && branchName.trim() !== '') {
|
|
526
|
+
uploadUrl.searchParams.set('branchName', branchName);
|
|
527
|
+
}
|
|
528
|
+
if (commitId != null && commitId.trim() !== '') {
|
|
529
|
+
uploadUrl.searchParams.set('commitId', commitId);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const response = await fetch(uploadUrl.toString(), {
|
|
533
|
+
method: 'POST',
|
|
534
|
+
body: formData,
|
|
535
|
+
headers: {
|
|
536
|
+
Authorization: authorization
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
if (!response.ok) {
|
|
541
|
+
const errorText = await response.text().catch(() => '');
|
|
542
|
+
throw new Error(`Attachment upload failed: status=${response.status}${errorText ? `, body=${errorText}` : ''}`);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return (await response.json()) as AttachmentUploadServerDto;
|
|
546
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const DEFAULT_SUPERBLOCKS_DOMAIN = 'app.superblocks.com';
|
|
2
|
+
|
|
3
|
+
export function isGitHubRemoteUrl(remoteUrl: string): boolean {
|
|
4
|
+
return /(^git@github\.com:)|(^https?:\/\/github\.com\/)|(^ssh:\/\/git@github\.com\/)/.test(remoteUrl.trim());
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function buildGithubSuperblocksSyncWorkflow(domain: string = DEFAULT_SUPERBLOCKS_DOMAIN): string {
|
|
8
|
+
return `name: Sync changes to Superblocks
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches:
|
|
13
|
+
- main
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
superblocks-sync:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
name: Sync to Superblocks
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
packages: read
|
|
23
|
+
steps:
|
|
24
|
+
- name: Checkout
|
|
25
|
+
uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
|
|
30
|
+
# Optional: needed only if the CLI version is private in GitHub Packages.
|
|
31
|
+
- name: Setup npm credentials
|
|
32
|
+
env:
|
|
33
|
+
NPM_AUTH_TOKEN: \${{ secrets.NPM_AUTH_TOKEN }}
|
|
34
|
+
run: |
|
|
35
|
+
if [ -n "$NPM_AUTH_TOKEN" ]; then
|
|
36
|
+
echo "@superblocksteam:registry=https://npm.pkg.github.com" >> .npmrc
|
|
37
|
+
echo "always-auth=true" >> .npmrc
|
|
38
|
+
echo "//npm.pkg.github.com/:_authToken=$NPM_AUTH_TOKEN" >> .npmrc
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
- name: Sync
|
|
42
|
+
uses: superblocksteam/sync-action@v1
|
|
43
|
+
env:
|
|
44
|
+
NPM_CONFIG_USERCONFIG: \${{ github.workspace }}/.npmrc
|
|
45
|
+
with:
|
|
46
|
+
token: \${{ secrets.SUPERBLOCKS_TOKEN }}
|
|
47
|
+
domain: ${domain}
|
|
48
|
+
path: .
|
|
49
|
+
sha: \${{ github.sha }}
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getSuperblocksDomainFromBaseUrl(superblocksBaseUrl: string): string {
|
|
54
|
+
const trimmed = superblocksBaseUrl.trim();
|
|
55
|
+
if (!trimmed) {
|
|
56
|
+
return DEFAULT_SUPERBLOCKS_DOMAIN;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
return new URL(trimmed).host || DEFAULT_SUPERBLOCKS_DOMAIN;
|
|
61
|
+
} catch {
|
|
62
|
+
return DEFAULT_SUPERBLOCKS_DOMAIN;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function buildGithubSuperblocksSyncWorkflowFromBaseUrl(superblocksBaseUrl: string): string {
|
|
67
|
+
return buildGithubSuperblocksSyncWorkflow(getSuperblocksDomainFromBaseUrl(superblocksBaseUrl));
|
|
68
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export type AiCreditTokenRates = {
|
|
2
|
-
inputTokenCost: number;
|
|
3
|
-
outputTokenCost: number;
|
|
4
|
-
cacheReadTokenCost: number;
|
|
5
|
-
cacheWriteTokenCost: number;
|
|
6
|
-
};
|
|
7
|
-
export declare const AI_CREDIT_COST_MULTIPLIER = 2;
|
|
8
|
-
export declare const AI_MODEL_CREDIT_RATES: {
|
|
9
|
-
readonly 'claude-haiku-4-5': {
|
|
10
|
-
readonly inputTokenCost: 0.000001;
|
|
11
|
-
readonly outputTokenCost: 0.000005;
|
|
12
|
-
readonly cacheReadTokenCost: 1e-7;
|
|
13
|
-
readonly cacheWriteTokenCost: 0.00000125;
|
|
14
|
-
};
|
|
15
|
-
readonly 'claude-opus-4-5': {
|
|
16
|
-
readonly inputTokenCost: 0.000005;
|
|
17
|
-
readonly outputTokenCost: 0.000025;
|
|
18
|
-
readonly cacheReadTokenCost: 5e-7;
|
|
19
|
-
readonly cacheWriteTokenCost: 0.00000625;
|
|
20
|
-
};
|
|
21
|
-
readonly 'claude-opus-4-6': {
|
|
22
|
-
readonly inputTokenCost: 0.000005;
|
|
23
|
-
readonly outputTokenCost: 0.000025;
|
|
24
|
-
readonly cacheReadTokenCost: 5e-7;
|
|
25
|
-
readonly cacheWriteTokenCost: 0.00000625;
|
|
26
|
-
};
|
|
27
|
-
readonly 'claude-sonnet-4-5': {
|
|
28
|
-
readonly inputTokenCost: 0.000003;
|
|
29
|
-
readonly outputTokenCost: 0.000015;
|
|
30
|
-
readonly cacheReadTokenCost: 3e-7;
|
|
31
|
-
readonly cacheWriteTokenCost: 0.00000375;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
export declare const AI_FALLBACK_CREDIT_RATES: AiCreditTokenRates;
|
|
35
|
-
export declare const resolveAiCreditRates: (model: string) => {
|
|
36
|
-
modelKey: string;
|
|
37
|
-
rates: AiCreditTokenRates;
|
|
38
|
-
usedFallback: boolean;
|
|
39
|
-
};
|
|
40
|
-
export declare const computeAiCreditUsage: (params: {
|
|
41
|
-
inputTokens: number;
|
|
42
|
-
outputTokens: number;
|
|
43
|
-
cachedReadTokens: number;
|
|
44
|
-
cachedWriteTokens: number;
|
|
45
|
-
rates: AiCreditTokenRates;
|
|
46
|
-
}) => number;
|
|
47
|
-
//# sourceMappingURL=credit-pricing.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"credit-pricing.d.ts","sourceRoot":"","sources":["../../../src/types/ai/credit-pricing.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;CAyBqB,CAAC;AAExD,eAAO,MAAM,wBAAwB,EAAE,kBAA+D,CAAC;AAcvG,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,KACZ;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;CAgBvB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,QAAQ;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,kBAAkB,CAAC;CAC3B,KAAG,MAOH,CAAC"}
|