@suphark/files-client 0.0.0-stage → 0.3.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.
@@ -0,0 +1,1297 @@
1
+ import { CreateUploadInput, CompleteUploadInput, FileAssetDto, ReplaceFileInput, CreateGrantInput, ListFilesQuery, SearchQuery, UpdateFileInput, BatchFilesInput, FileReferenceInput, FileReferenceDto, CreateFolderInput, UpdateFolderInput, LinkSourceInput, FilesManifest, AdoptFileInput } from '@pi/files-contracts';
2
+ export * from '@pi/files-contracts';
3
+ import { H as HttpOptions, a as UploadApi, b as UploadSource, c as PerformUploadOptions } from './upload-D79TA4qU.js';
4
+ export { P as PiFilesError, U as UploadProgress, f as fileFingerprint, p as performUpload, d as putBytes } from './upload-D79TA4qU.js';
5
+
6
+ interface PiFilesOptions extends HttpOptions {
7
+ }
8
+ /**
9
+ * client ของ Pi Files — ใช้ได้ทั้ง server (appKey / getUserToken) และ browser (credentials: "include" ภายใน Pi Files เอง)
10
+ * ทุก method โยน PiFilesError เมื่อ API ตอบ error
11
+ */
12
+ declare function createPiFiles(options: PiFilesOptions): {
13
+ options: PiFilesOptions;
14
+ uploads: {
15
+ create: (input: CreateUploadInput) => Promise<{
16
+ kind: "put";
17
+ uploadId: string;
18
+ fileId: string;
19
+ url: string;
20
+ method: "PUT";
21
+ headers: Record<string, string>;
22
+ expiresAt: string;
23
+ } | {
24
+ kind: "multipart";
25
+ uploadId: string;
26
+ fileId: string;
27
+ partSizeBytes: number;
28
+ partCount: number;
29
+ expiresAt: string;
30
+ }>;
31
+ partUrls: (uploadId: string, partNumbers: number[]) => Promise<{
32
+ parts: {
33
+ partNumber: number;
34
+ url: string;
35
+ expiresAt: string;
36
+ method?: "PUT" | "POST" | undefined;
37
+ headers?: Record<string, string> | undefined;
38
+ }[];
39
+ }>;
40
+ complete: (uploadId: string, parts?: CompleteUploadInput["parts"]) => Promise<{
41
+ id: string;
42
+ filename: string;
43
+ mimeType: string;
44
+ sizeBytes: string;
45
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
46
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
47
+ ownerType: "USER" | "APP";
48
+ ownerId: string;
49
+ appKey: string | null;
50
+ folderId: string | null;
51
+ etag: string | null;
52
+ checksumSha256: string | null;
53
+ versionCount: number;
54
+ refCount: number;
55
+ metadata: Record<string, unknown>;
56
+ createdById: string | null;
57
+ createdAt: string;
58
+ updatedAt: string;
59
+ trashedAt: string | null;
60
+ contentPath: string;
61
+ previewPath: string | null;
62
+ publicUrl: string | null;
63
+ storage: {
64
+ bucketKey: string;
65
+ bucketLabel: string | null;
66
+ kind: string;
67
+ providerName: string;
68
+ sourceUrl?: string | null | undefined;
69
+ linked?: boolean | undefined;
70
+ } | null;
71
+ }>;
72
+ abort: (uploadId: string) => Promise<void>;
73
+ };
74
+ uploadApi: UploadApi;
75
+ upload: (source: UploadSource, input: CreateUploadInput, opts?: PerformUploadOptions) => Promise<FileAssetDto>;
76
+ replace: (fileId: string, source: UploadSource, input: ReplaceFileInput, opts?: PerformUploadOptions) => Promise<FileAssetDto>;
77
+ files: {
78
+ grant: (fileId: string, input?: Partial<CreateGrantInput>) => Promise<{
79
+ url: string;
80
+ expiresAt: string;
81
+ }>;
82
+ get: (id: string) => Promise<{
83
+ id: string;
84
+ filename: string;
85
+ mimeType: string;
86
+ sizeBytes: string;
87
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
88
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
89
+ ownerType: "USER" | "APP";
90
+ ownerId: string;
91
+ appKey: string | null;
92
+ folderId: string | null;
93
+ etag: string | null;
94
+ checksumSha256: string | null;
95
+ versionCount: number;
96
+ refCount: number;
97
+ metadata: Record<string, unknown>;
98
+ createdById: string | null;
99
+ createdAt: string;
100
+ updatedAt: string;
101
+ trashedAt: string | null;
102
+ contentPath: string;
103
+ previewPath: string | null;
104
+ publicUrl: string | null;
105
+ storage: {
106
+ bucketKey: string;
107
+ bucketLabel: string | null;
108
+ kind: string;
109
+ providerName: string;
110
+ sourceUrl?: string | null | undefined;
111
+ linked?: boolean | undefined;
112
+ } | null;
113
+ }>;
114
+ /** ตำแหน่งจริง + สิทธิ์ที่ต้นทาง (Google Drive) + แชร์สาธารณะได้ไหม — ใช้ตอบ "ไฟล์นี้ส่งให้ใครได้บ้าง" */
115
+ access: (id: string) => Promise<{
116
+ provider: string;
117
+ bucketKey: string;
118
+ objectKey: string;
119
+ sourceUrl: string | null;
120
+ scope: "unknown" | "anyone" | "domain" | "restricted" | "pi-files";
121
+ domains: string[];
122
+ people: {
123
+ email: string;
124
+ role: string;
125
+ name: string | null;
126
+ }[];
127
+ publicLinkAllowed: boolean;
128
+ reason: string | null;
129
+ }>;
130
+ list: (query?: Partial<ListFilesQuery>) => Promise<{
131
+ items: FileAssetDto[];
132
+ nextCursor: string | null;
133
+ }>;
134
+ search: (query: Partial<SearchQuery> & {
135
+ q: string;
136
+ }) => Promise<{
137
+ items: FileAssetDto[];
138
+ nextCursor: string | null;
139
+ }>;
140
+ update: (id: string, patch: UpdateFileInput) => Promise<{
141
+ id: string;
142
+ filename: string;
143
+ mimeType: string;
144
+ sizeBytes: string;
145
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
146
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
147
+ ownerType: "USER" | "APP";
148
+ ownerId: string;
149
+ appKey: string | null;
150
+ folderId: string | null;
151
+ etag: string | null;
152
+ checksumSha256: string | null;
153
+ versionCount: number;
154
+ refCount: number;
155
+ metadata: Record<string, unknown>;
156
+ createdById: string | null;
157
+ createdAt: string;
158
+ updatedAt: string;
159
+ trashedAt: string | null;
160
+ contentPath: string;
161
+ previewPath: string | null;
162
+ publicUrl: string | null;
163
+ storage: {
164
+ bucketKey: string;
165
+ bucketLabel: string | null;
166
+ kind: string;
167
+ providerName: string;
168
+ sourceUrl?: string | null | undefined;
169
+ linked?: boolean | undefined;
170
+ } | null;
171
+ }>;
172
+ trash: (id: string) => Promise<{
173
+ id: string;
174
+ filename: string;
175
+ mimeType: string;
176
+ sizeBytes: string;
177
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
178
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
179
+ ownerType: "USER" | "APP";
180
+ ownerId: string;
181
+ appKey: string | null;
182
+ folderId: string | null;
183
+ etag: string | null;
184
+ checksumSha256: string | null;
185
+ versionCount: number;
186
+ refCount: number;
187
+ metadata: Record<string, unknown>;
188
+ createdById: string | null;
189
+ createdAt: string;
190
+ updatedAt: string;
191
+ trashedAt: string | null;
192
+ contentPath: string;
193
+ previewPath: string | null;
194
+ publicUrl: string | null;
195
+ storage: {
196
+ bucketKey: string;
197
+ bucketLabel: string | null;
198
+ kind: string;
199
+ providerName: string;
200
+ sourceUrl?: string | null | undefined;
201
+ linked?: boolean | undefined;
202
+ } | null;
203
+ }>;
204
+ delete: (id: string) => Promise<{
205
+ id: string;
206
+ filename: string;
207
+ mimeType: string;
208
+ sizeBytes: string;
209
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
210
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
211
+ ownerType: "USER" | "APP";
212
+ ownerId: string;
213
+ appKey: string | null;
214
+ folderId: string | null;
215
+ etag: string | null;
216
+ checksumSha256: string | null;
217
+ versionCount: number;
218
+ refCount: number;
219
+ metadata: Record<string, unknown>;
220
+ createdById: string | null;
221
+ createdAt: string;
222
+ updatedAt: string;
223
+ trashedAt: string | null;
224
+ contentPath: string;
225
+ previewPath: string | null;
226
+ publicUrl: string | null;
227
+ storage: {
228
+ bucketKey: string;
229
+ bucketLabel: string | null;
230
+ kind: string;
231
+ providerName: string;
232
+ sourceUrl?: string | null | undefined;
233
+ linked?: boolean | undefined;
234
+ } | null;
235
+ }>;
236
+ restore: (id: string) => Promise<{
237
+ id: string;
238
+ filename: string;
239
+ mimeType: string;
240
+ sizeBytes: string;
241
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
242
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
243
+ ownerType: "USER" | "APP";
244
+ ownerId: string;
245
+ appKey: string | null;
246
+ folderId: string | null;
247
+ etag: string | null;
248
+ checksumSha256: string | null;
249
+ versionCount: number;
250
+ refCount: number;
251
+ metadata: Record<string, unknown>;
252
+ createdById: string | null;
253
+ createdAt: string;
254
+ updatedAt: string;
255
+ trashedAt: string | null;
256
+ contentPath: string;
257
+ previewPath: string | null;
258
+ publicUrl: string | null;
259
+ storage: {
260
+ bucketKey: string;
261
+ bucketLabel: string | null;
262
+ kind: string;
263
+ providerName: string;
264
+ sourceUrl?: string | null | undefined;
265
+ linked?: boolean | undefined;
266
+ } | null;
267
+ }>;
268
+ batch: (input: BatchFilesInput) => Promise<{
269
+ ok: string[];
270
+ failed: {
271
+ id: string;
272
+ code: string;
273
+ detail: string;
274
+ }[];
275
+ }>;
276
+ /** URL ที่ browser ใช้ได้ทันที (อายุสั้น) — server ของ consumer เรียกแล้วส่งต่อ/redirect */
277
+ contentUrl: (id: string, opts?: {
278
+ download?: boolean;
279
+ ttl?: number;
280
+ }) => Promise<{
281
+ url: string;
282
+ expiresAt: string;
283
+ }>;
284
+ /** stream ผ่าน Pi Files (รองรับ Range) — คืน Response ดิบให้ proxy ต่อ */
285
+ stream: (id: string, opts?: {
286
+ range?: string | null;
287
+ download?: boolean;
288
+ signal?: AbortSignal;
289
+ }) => Promise<Response>;
290
+ /** path relative ต่อ baseUrl สำหรับ mode=redirect (ใช้ในลิงก์ที่ browser มี token/cookie ของ Pi Files) */
291
+ contentPath: (id: string, opts?: {
292
+ download?: boolean;
293
+ }) => string;
294
+ /**
295
+ * ภาพตัวอย่าง webp (sm 256px / lg 1024px) แบบ stream — ใช้ฝั่ง server ของ consumer
296
+ * ฝั่ง browser ของ consumer ใช้ `handlers.preview` ของ `/next`; ไฟล์ที่ไม่มีตัวอย่าง (`previewPath` null) ตอบ 404
297
+ */
298
+ preview: (id: string, opts?: {
299
+ size?: "sm" | "lg";
300
+ signal?: AbortSignal;
301
+ }) => Promise<Response>;
302
+ /** ticket สำหรับอัปโหลดเนื้อหาใหม่ทับไฟล์เดิม (id/ชื่อ/แชร์/reference คงเดิม) — ใช้ `replace()` ครบวงจรแทนได้ */
303
+ replace: (id: string, input: ReplaceFileInput) => Promise<{
304
+ kind: "put";
305
+ uploadId: string;
306
+ fileId: string;
307
+ url: string;
308
+ method: "PUT";
309
+ headers: Record<string, string>;
310
+ expiresAt: string;
311
+ } | {
312
+ kind: "multipart";
313
+ uploadId: string;
314
+ fileId: string;
315
+ partSizeBytes: number;
316
+ partCount: number;
317
+ expiresAt: string;
318
+ }>;
319
+ /** ฉบับปัจจุบัน + เวอร์ชันเก่า (ใหม่ → เก่า) */
320
+ versions: (id: string) => Promise<{
321
+ versionNo: number;
322
+ current: boolean;
323
+ filename: string;
324
+ mimeType: string;
325
+ sizeBytes: string;
326
+ createdById: string | null;
327
+ createdAt: string;
328
+ expiresAt: string | null;
329
+ }[]>;
330
+ /** เวอร์ชันเก่ากลับมาเป็นฉบับปัจจุบัน (ฉบับปัจจุบันเดิมเก็บเป็นประวัติ) */
331
+ restoreVersion: (id: string, versionNo: number) => Promise<{
332
+ id: string;
333
+ filename: string;
334
+ mimeType: string;
335
+ sizeBytes: string;
336
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
337
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
338
+ ownerType: "USER" | "APP";
339
+ ownerId: string;
340
+ appKey: string | null;
341
+ folderId: string | null;
342
+ etag: string | null;
343
+ checksumSha256: string | null;
344
+ versionCount: number;
345
+ refCount: number;
346
+ metadata: Record<string, unknown>;
347
+ createdById: string | null;
348
+ createdAt: string;
349
+ updatedAt: string;
350
+ trashedAt: string | null;
351
+ contentPath: string;
352
+ previewPath: string | null;
353
+ publicUrl: string | null;
354
+ storage: {
355
+ bucketKey: string;
356
+ bucketLabel: string | null;
357
+ kind: string;
358
+ providerName: string;
359
+ sourceUrl?: string | null | undefined;
360
+ linked?: boolean | undefined;
361
+ } | null;
362
+ }>;
363
+ deleteVersion: (id: string, versionNo: number) => Promise<{
364
+ ok: true;
365
+ }>;
366
+ versionContentUrl: (id: string, versionNo: number, opts?: {
367
+ download?: boolean;
368
+ ttl?: number;
369
+ }) => Promise<{
370
+ url: string;
371
+ expiresAt: string;
372
+ }>;
373
+ };
374
+ references: {
375
+ attach: (fileId: string, ref: FileReferenceInput) => Promise<{
376
+ featureKey: string;
377
+ entityType: string;
378
+ entityId: string;
379
+ role: string;
380
+ id: string;
381
+ appKey: string;
382
+ createdAt: string;
383
+ }>;
384
+ detach: (fileId: string, ref: FileReferenceInput) => Promise<{
385
+ ok: true;
386
+ refCount: number;
387
+ }>;
388
+ listOf: (fileId: string) => Promise<{
389
+ featureKey: string;
390
+ entityType: string;
391
+ entityId: string;
392
+ role: string;
393
+ id: string;
394
+ appKey: string;
395
+ createdAt: string;
396
+ }[]>;
397
+ /** ย้าย reference แบบ atomic เช่น draft → ระเบียนจริง (ไฟล์ไม่กลายเป็นกำพร้าระหว่างทาง) */
398
+ move: (fileId: string, from: FileReferenceInput, to: FileReferenceInput) => Promise<{
399
+ featureKey: string;
400
+ entityType: string;
401
+ entityId: string;
402
+ role: string;
403
+ id: string;
404
+ appKey: string;
405
+ createdAt: string;
406
+ }>;
407
+ byEntity: (entityType: string, entityId: string, featureKey?: string) => Promise<{
408
+ reference: FileReferenceDto;
409
+ file: FileAssetDto;
410
+ }[]>;
411
+ };
412
+ folders: {
413
+ get: (id?: string) => Promise<{
414
+ folder: {
415
+ id: string;
416
+ name: string;
417
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
418
+ ownerType: "USER" | "APP";
419
+ ownerId: string;
420
+ parentId: string | null;
421
+ path: string;
422
+ depth: number;
423
+ status: "ACTIVE" | "TRASHED";
424
+ createdAt: string;
425
+ updatedAt: string;
426
+ sourceId?: string | null | undefined;
427
+ externalId?: string | null | undefined;
428
+ };
429
+ access: "view" | "owner" | "edit";
430
+ breadcrumb: {
431
+ id: string;
432
+ name: string;
433
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
434
+ }[];
435
+ children: {
436
+ id: string;
437
+ name: string;
438
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
439
+ ownerType: "USER" | "APP";
440
+ ownerId: string;
441
+ parentId: string | null;
442
+ path: string;
443
+ depth: number;
444
+ status: "ACTIVE" | "TRASHED";
445
+ createdAt: string;
446
+ updatedAt: string;
447
+ sourceId?: string | null | undefined;
448
+ externalId?: string | null | undefined;
449
+ }[];
450
+ }>;
451
+ tree: (root?: string, depth?: number) => Promise<unknown>;
452
+ create: (input: CreateFolderInput) => Promise<{
453
+ id: string;
454
+ name: string;
455
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
456
+ ownerType: "USER" | "APP";
457
+ ownerId: string;
458
+ parentId: string | null;
459
+ path: string;
460
+ depth: number;
461
+ status: "ACTIVE" | "TRASHED";
462
+ createdAt: string;
463
+ updatedAt: string;
464
+ sourceId?: string | null | undefined;
465
+ externalId?: string | null | undefined;
466
+ }>;
467
+ update: (id: string, patch: UpdateFolderInput) => Promise<{
468
+ id: string;
469
+ name: string;
470
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
471
+ ownerType: "USER" | "APP";
472
+ ownerId: string;
473
+ parentId: string | null;
474
+ path: string;
475
+ depth: number;
476
+ status: "ACTIVE" | "TRASHED";
477
+ createdAt: string;
478
+ updatedAt: string;
479
+ sourceId?: string | null | undefined;
480
+ externalId?: string | null | undefined;
481
+ }>;
482
+ trash: (id: string) => Promise<{
483
+ ok: true;
484
+ }>;
485
+ restore: (id: string) => Promise<{
486
+ id: string;
487
+ name: string;
488
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
489
+ ownerType: "USER" | "APP";
490
+ ownerId: string;
491
+ parentId: string | null;
492
+ path: string;
493
+ depth: number;
494
+ status: "ACTIVE" | "TRASHED";
495
+ createdAt: string;
496
+ updatedAt: string;
497
+ sourceId?: string | null | undefined;
498
+ externalId?: string | null | undefined;
499
+ }>;
500
+ /** ไฟล์ + โฟลเดอร์ใต้โฟลเดอร์ (recursive) พร้อม relativePath/md5/modifiedTime/providerFileId — ใช้ทำ fingerprint */
501
+ contents: (id: string, opts?: {
502
+ recursive?: boolean;
503
+ }) => Promise<{
504
+ folderId: string;
505
+ sourceId: string | null;
506
+ items: {
507
+ id: string;
508
+ isFolder: boolean;
509
+ name: string;
510
+ relativePath: string;
511
+ parentId: string | null;
512
+ mimeType: string | null;
513
+ sizeBytes: string | null;
514
+ md5: string | null;
515
+ modifiedTime: string | null;
516
+ providerFileId: string | null;
517
+ webViewLink: string | null;
518
+ status: string;
519
+ }[];
520
+ }>;
521
+ /** หา/สร้างโฟลเดอร์ตามชื่อ (ใต้ linked source = สร้างใน Google Drive จริง) */
522
+ ensurePath: (id: string, names: string[]) => Promise<{
523
+ id: string;
524
+ name: string;
525
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
526
+ ownerType: "USER" | "APP";
527
+ ownerId: string;
528
+ parentId: string | null;
529
+ path: string;
530
+ depth: number;
531
+ status: "ACTIVE" | "TRASHED";
532
+ createdAt: string;
533
+ updatedAt: string;
534
+ sourceId?: string | null | undefined;
535
+ externalId?: string | null | undefined;
536
+ }>;
537
+ };
538
+ sources: {
539
+ /** ผูก (idempotent — ผูกซ้ำ = source เดิม) แล้ว sync ทั้งต้นทันที */
540
+ link: (input: LinkSourceInput) => Promise<{
541
+ id: string;
542
+ appKey: string;
543
+ bucketKey: string;
544
+ folderId: string;
545
+ externalFolderId: string;
546
+ sourceUrl: string;
547
+ label: string | null;
548
+ status: "ACTIVE" | "ERROR" | "PAUSED";
549
+ lastSyncedAt: string | null;
550
+ lastError: string | null;
551
+ createdAt: string;
552
+ stats?: {
553
+ folders: number;
554
+ files: number;
555
+ created: number;
556
+ updated: number;
557
+ removed: number;
558
+ } | undefined;
559
+ }>;
560
+ list: () => Promise<{
561
+ id: string;
562
+ appKey: string;
563
+ bucketKey: string;
564
+ folderId: string;
565
+ externalFolderId: string;
566
+ sourceUrl: string;
567
+ label: string | null;
568
+ status: "ACTIVE" | "ERROR" | "PAUSED";
569
+ lastSyncedAt: string | null;
570
+ lastError: string | null;
571
+ createdAt: string;
572
+ stats?: {
573
+ folders: number;
574
+ files: number;
575
+ created: number;
576
+ updated: number;
577
+ removed: number;
578
+ } | undefined;
579
+ }[]>;
580
+ get: (id: string) => Promise<{
581
+ id: string;
582
+ appKey: string;
583
+ bucketKey: string;
584
+ folderId: string;
585
+ externalFolderId: string;
586
+ sourceUrl: string;
587
+ label: string | null;
588
+ status: "ACTIVE" | "ERROR" | "PAUSED";
589
+ lastSyncedAt: string | null;
590
+ lastError: string | null;
591
+ createdAt: string;
592
+ stats?: {
593
+ folders: number;
594
+ files: number;
595
+ created: number;
596
+ updated: number;
597
+ removed: number;
598
+ } | undefined;
599
+ }>;
600
+ /** sync ทั้งต้นตอนนี้ (ปกติ Pi Files ตามการเปลี่ยนแปลงใน Drive ให้ทุก 5 นาที + webhook) */
601
+ sync: (id: string) => Promise<{
602
+ id: string;
603
+ appKey: string;
604
+ bucketKey: string;
605
+ folderId: string;
606
+ externalFolderId: string;
607
+ sourceUrl: string;
608
+ label: string | null;
609
+ status: "ACTIVE" | "ERROR" | "PAUSED";
610
+ lastSyncedAt: string | null;
611
+ lastError: string | null;
612
+ createdAt: string;
613
+ stats?: {
614
+ folders: number;
615
+ files: number;
616
+ created: number;
617
+ updated: number;
618
+ removed: number;
619
+ } | undefined;
620
+ }>;
621
+ /** เลิกผูก — ไม่แตะ Google Drive; ไฟล์ที่ยังมี reference = 409 SOURCE_REFERENCED */
622
+ unlink: (id: string) => Promise<{
623
+ ok: true;
624
+ files: number;
625
+ folders: number;
626
+ }>;
627
+ };
628
+ quota: {
629
+ get: (scope?: "user" | "app" | "tenant") => Promise<{
630
+ scope: "app" | "tenant" | "user";
631
+ scopeId: string;
632
+ bytesUsed: string;
633
+ fileCount: number;
634
+ quotaBytes: string | null;
635
+ }>;
636
+ };
637
+ manifest: {
638
+ sync: (input: FilesManifest) => Promise<{
639
+ created: string[];
640
+ updated: string[];
641
+ deprecated: string[];
642
+ }>;
643
+ };
644
+ migration: {
645
+ /** รับ object ที่มีอยู่แล้วใน bucket เข้าทะเบียน ณ ที่เดิม (ไม่คัดลอก) — idempotent ด้วย externalSource+externalId */
646
+ adopt: (input: AdoptFileInput) => Promise<{
647
+ status: "created" | "existing";
648
+ fileId: string;
649
+ }>;
650
+ };
651
+ /** client เดิมแต่ใช้ token ของผู้ใช้แทน appKey (user-context ต่อ request) */
652
+ withUser: (token: string) => {
653
+ options: PiFilesOptions;
654
+ uploads: {
655
+ create: (input: CreateUploadInput) => Promise<{
656
+ kind: "put";
657
+ uploadId: string;
658
+ fileId: string;
659
+ url: string;
660
+ method: "PUT";
661
+ headers: Record<string, string>;
662
+ expiresAt: string;
663
+ } | {
664
+ kind: "multipart";
665
+ uploadId: string;
666
+ fileId: string;
667
+ partSizeBytes: number;
668
+ partCount: number;
669
+ expiresAt: string;
670
+ }>;
671
+ partUrls: (uploadId: string, partNumbers: number[]) => Promise<{
672
+ parts: {
673
+ partNumber: number;
674
+ url: string;
675
+ expiresAt: string;
676
+ method?: "PUT" | "POST" | undefined;
677
+ headers?: Record<string, string> | undefined;
678
+ }[];
679
+ }>;
680
+ complete: (uploadId: string, parts?: CompleteUploadInput["parts"]) => Promise<{
681
+ id: string;
682
+ filename: string;
683
+ mimeType: string;
684
+ sizeBytes: string;
685
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
686
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
687
+ ownerType: "USER" | "APP";
688
+ ownerId: string;
689
+ appKey: string | null;
690
+ folderId: string | null;
691
+ etag: string | null;
692
+ checksumSha256: string | null;
693
+ versionCount: number;
694
+ refCount: number;
695
+ metadata: Record<string, unknown>;
696
+ createdById: string | null;
697
+ createdAt: string;
698
+ updatedAt: string;
699
+ trashedAt: string | null;
700
+ contentPath: string;
701
+ previewPath: string | null;
702
+ publicUrl: string | null;
703
+ storage: {
704
+ bucketKey: string;
705
+ bucketLabel: string | null;
706
+ kind: string;
707
+ providerName: string;
708
+ sourceUrl?: string | null | undefined;
709
+ linked?: boolean | undefined;
710
+ } | null;
711
+ }>;
712
+ abort: (uploadId: string) => Promise<void>;
713
+ };
714
+ uploadApi: UploadApi;
715
+ upload: (source: UploadSource, input: CreateUploadInput, opts?: PerformUploadOptions) => Promise<FileAssetDto>;
716
+ replace: (fileId: string, source: UploadSource, input: ReplaceFileInput, opts?: PerformUploadOptions) => Promise<FileAssetDto>;
717
+ files: {
718
+ grant: (fileId: string, input?: Partial<CreateGrantInput>) => Promise<{
719
+ url: string;
720
+ expiresAt: string;
721
+ }>;
722
+ get: (id: string) => Promise<{
723
+ id: string;
724
+ filename: string;
725
+ mimeType: string;
726
+ sizeBytes: string;
727
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
728
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
729
+ ownerType: "USER" | "APP";
730
+ ownerId: string;
731
+ appKey: string | null;
732
+ folderId: string | null;
733
+ etag: string | null;
734
+ checksumSha256: string | null;
735
+ versionCount: number;
736
+ refCount: number;
737
+ metadata: Record<string, unknown>;
738
+ createdById: string | null;
739
+ createdAt: string;
740
+ updatedAt: string;
741
+ trashedAt: string | null;
742
+ contentPath: string;
743
+ previewPath: string | null;
744
+ publicUrl: string | null;
745
+ storage: {
746
+ bucketKey: string;
747
+ bucketLabel: string | null;
748
+ kind: string;
749
+ providerName: string;
750
+ sourceUrl?: string | null | undefined;
751
+ linked?: boolean | undefined;
752
+ } | null;
753
+ }>;
754
+ /** ตำแหน่งจริง + สิทธิ์ที่ต้นทาง (Google Drive) + แชร์สาธารณะได้ไหม — ใช้ตอบ "ไฟล์นี้ส่งให้ใครได้บ้าง" */
755
+ access: (id: string) => Promise<{
756
+ provider: string;
757
+ bucketKey: string;
758
+ objectKey: string;
759
+ sourceUrl: string | null;
760
+ scope: "unknown" | "anyone" | "domain" | "restricted" | "pi-files";
761
+ domains: string[];
762
+ people: {
763
+ email: string;
764
+ role: string;
765
+ name: string | null;
766
+ }[];
767
+ publicLinkAllowed: boolean;
768
+ reason: string | null;
769
+ }>;
770
+ list: (query?: Partial<ListFilesQuery>) => Promise<{
771
+ items: FileAssetDto[];
772
+ nextCursor: string | null;
773
+ }>;
774
+ search: (query: Partial<SearchQuery> & {
775
+ q: string;
776
+ }) => Promise<{
777
+ items: FileAssetDto[];
778
+ nextCursor: string | null;
779
+ }>;
780
+ update: (id: string, patch: UpdateFileInput) => Promise<{
781
+ id: string;
782
+ filename: string;
783
+ mimeType: string;
784
+ sizeBytes: string;
785
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
786
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
787
+ ownerType: "USER" | "APP";
788
+ ownerId: string;
789
+ appKey: string | null;
790
+ folderId: string | null;
791
+ etag: string | null;
792
+ checksumSha256: string | null;
793
+ versionCount: number;
794
+ refCount: number;
795
+ metadata: Record<string, unknown>;
796
+ createdById: string | null;
797
+ createdAt: string;
798
+ updatedAt: string;
799
+ trashedAt: string | null;
800
+ contentPath: string;
801
+ previewPath: string | null;
802
+ publicUrl: string | null;
803
+ storage: {
804
+ bucketKey: string;
805
+ bucketLabel: string | null;
806
+ kind: string;
807
+ providerName: string;
808
+ sourceUrl?: string | null | undefined;
809
+ linked?: boolean | undefined;
810
+ } | null;
811
+ }>;
812
+ trash: (id: string) => Promise<{
813
+ id: string;
814
+ filename: string;
815
+ mimeType: string;
816
+ sizeBytes: string;
817
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
818
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
819
+ ownerType: "USER" | "APP";
820
+ ownerId: string;
821
+ appKey: string | null;
822
+ folderId: string | null;
823
+ etag: string | null;
824
+ checksumSha256: string | null;
825
+ versionCount: number;
826
+ refCount: number;
827
+ metadata: Record<string, unknown>;
828
+ createdById: string | null;
829
+ createdAt: string;
830
+ updatedAt: string;
831
+ trashedAt: string | null;
832
+ contentPath: string;
833
+ previewPath: string | null;
834
+ publicUrl: string | null;
835
+ storage: {
836
+ bucketKey: string;
837
+ bucketLabel: string | null;
838
+ kind: string;
839
+ providerName: string;
840
+ sourceUrl?: string | null | undefined;
841
+ linked?: boolean | undefined;
842
+ } | null;
843
+ }>;
844
+ delete: (id: string) => Promise<{
845
+ id: string;
846
+ filename: string;
847
+ mimeType: string;
848
+ sizeBytes: string;
849
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
850
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
851
+ ownerType: "USER" | "APP";
852
+ ownerId: string;
853
+ appKey: string | null;
854
+ folderId: string | null;
855
+ etag: string | null;
856
+ checksumSha256: string | null;
857
+ versionCount: number;
858
+ refCount: number;
859
+ metadata: Record<string, unknown>;
860
+ createdById: string | null;
861
+ createdAt: string;
862
+ updatedAt: string;
863
+ trashedAt: string | null;
864
+ contentPath: string;
865
+ previewPath: string | null;
866
+ publicUrl: string | null;
867
+ storage: {
868
+ bucketKey: string;
869
+ bucketLabel: string | null;
870
+ kind: string;
871
+ providerName: string;
872
+ sourceUrl?: string | null | undefined;
873
+ linked?: boolean | undefined;
874
+ } | null;
875
+ }>;
876
+ restore: (id: string) => Promise<{
877
+ id: string;
878
+ filename: string;
879
+ mimeType: string;
880
+ sizeBytes: string;
881
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
882
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
883
+ ownerType: "USER" | "APP";
884
+ ownerId: string;
885
+ appKey: string | null;
886
+ folderId: string | null;
887
+ etag: string | null;
888
+ checksumSha256: string | null;
889
+ versionCount: number;
890
+ refCount: number;
891
+ metadata: Record<string, unknown>;
892
+ createdById: string | null;
893
+ createdAt: string;
894
+ updatedAt: string;
895
+ trashedAt: string | null;
896
+ contentPath: string;
897
+ previewPath: string | null;
898
+ publicUrl: string | null;
899
+ storage: {
900
+ bucketKey: string;
901
+ bucketLabel: string | null;
902
+ kind: string;
903
+ providerName: string;
904
+ sourceUrl?: string | null | undefined;
905
+ linked?: boolean | undefined;
906
+ } | null;
907
+ }>;
908
+ batch: (input: BatchFilesInput) => Promise<{
909
+ ok: string[];
910
+ failed: {
911
+ id: string;
912
+ code: string;
913
+ detail: string;
914
+ }[];
915
+ }>;
916
+ /** URL ที่ browser ใช้ได้ทันที (อายุสั้น) — server ของ consumer เรียกแล้วส่งต่อ/redirect */
917
+ contentUrl: (id: string, opts?: {
918
+ download?: boolean;
919
+ ttl?: number;
920
+ }) => Promise<{
921
+ url: string;
922
+ expiresAt: string;
923
+ }>;
924
+ /** stream ผ่าน Pi Files (รองรับ Range) — คืน Response ดิบให้ proxy ต่อ */
925
+ stream: (id: string, opts?: {
926
+ range?: string | null;
927
+ download?: boolean;
928
+ signal?: AbortSignal;
929
+ }) => Promise<Response>;
930
+ /** path relative ต่อ baseUrl สำหรับ mode=redirect (ใช้ในลิงก์ที่ browser มี token/cookie ของ Pi Files) */
931
+ contentPath: (id: string, opts?: {
932
+ download?: boolean;
933
+ }) => string;
934
+ /**
935
+ * ภาพตัวอย่าง webp (sm 256px / lg 1024px) แบบ stream — ใช้ฝั่ง server ของ consumer
936
+ * ฝั่ง browser ของ consumer ใช้ `handlers.preview` ของ `/next`; ไฟล์ที่ไม่มีตัวอย่าง (`previewPath` null) ตอบ 404
937
+ */
938
+ preview: (id: string, opts?: {
939
+ size?: "sm" | "lg";
940
+ signal?: AbortSignal;
941
+ }) => Promise<Response>;
942
+ /** ticket สำหรับอัปโหลดเนื้อหาใหม่ทับไฟล์เดิม (id/ชื่อ/แชร์/reference คงเดิม) — ใช้ `replace()` ครบวงจรแทนได้ */
943
+ replace: (id: string, input: ReplaceFileInput) => Promise<{
944
+ kind: "put";
945
+ uploadId: string;
946
+ fileId: string;
947
+ url: string;
948
+ method: "PUT";
949
+ headers: Record<string, string>;
950
+ expiresAt: string;
951
+ } | {
952
+ kind: "multipart";
953
+ uploadId: string;
954
+ fileId: string;
955
+ partSizeBytes: number;
956
+ partCount: number;
957
+ expiresAt: string;
958
+ }>;
959
+ /** ฉบับปัจจุบัน + เวอร์ชันเก่า (ใหม่ → เก่า) */
960
+ versions: (id: string) => Promise<{
961
+ versionNo: number;
962
+ current: boolean;
963
+ filename: string;
964
+ mimeType: string;
965
+ sizeBytes: string;
966
+ createdById: string | null;
967
+ createdAt: string;
968
+ expiresAt: string | null;
969
+ }[]>;
970
+ /** เวอร์ชันเก่ากลับมาเป็นฉบับปัจจุบัน (ฉบับปัจจุบันเดิมเก็บเป็นประวัติ) */
971
+ restoreVersion: (id: string, versionNo: number) => Promise<{
972
+ id: string;
973
+ filename: string;
974
+ mimeType: string;
975
+ sizeBytes: string;
976
+ status: "UPLOADING" | "ACTIVE" | "ORPHAN_CANDIDATE" | "TRASHED" | "PENDING_DELETE" | "MISSING" | "DELETED" | "ERROR";
977
+ visibility: "PRIVATE" | "TENANT" | "PUBLIC";
978
+ ownerType: "USER" | "APP";
979
+ ownerId: string;
980
+ appKey: string | null;
981
+ folderId: string | null;
982
+ etag: string | null;
983
+ checksumSha256: string | null;
984
+ versionCount: number;
985
+ refCount: number;
986
+ metadata: Record<string, unknown>;
987
+ createdById: string | null;
988
+ createdAt: string;
989
+ updatedAt: string;
990
+ trashedAt: string | null;
991
+ contentPath: string;
992
+ previewPath: string | null;
993
+ publicUrl: string | null;
994
+ storage: {
995
+ bucketKey: string;
996
+ bucketLabel: string | null;
997
+ kind: string;
998
+ providerName: string;
999
+ sourceUrl?: string | null | undefined;
1000
+ linked?: boolean | undefined;
1001
+ } | null;
1002
+ }>;
1003
+ deleteVersion: (id: string, versionNo: number) => Promise<{
1004
+ ok: true;
1005
+ }>;
1006
+ versionContentUrl: (id: string, versionNo: number, opts?: {
1007
+ download?: boolean;
1008
+ ttl?: number;
1009
+ }) => Promise<{
1010
+ url: string;
1011
+ expiresAt: string;
1012
+ }>;
1013
+ };
1014
+ references: {
1015
+ attach: (fileId: string, ref: FileReferenceInput) => Promise<{
1016
+ featureKey: string;
1017
+ entityType: string;
1018
+ entityId: string;
1019
+ role: string;
1020
+ id: string;
1021
+ appKey: string;
1022
+ createdAt: string;
1023
+ }>;
1024
+ detach: (fileId: string, ref: FileReferenceInput) => Promise<{
1025
+ ok: true;
1026
+ refCount: number;
1027
+ }>;
1028
+ listOf: (fileId: string) => Promise<{
1029
+ featureKey: string;
1030
+ entityType: string;
1031
+ entityId: string;
1032
+ role: string;
1033
+ id: string;
1034
+ appKey: string;
1035
+ createdAt: string;
1036
+ }[]>;
1037
+ /** ย้าย reference แบบ atomic เช่น draft → ระเบียนจริง (ไฟล์ไม่กลายเป็นกำพร้าระหว่างทาง) */
1038
+ move: (fileId: string, from: FileReferenceInput, to: FileReferenceInput) => Promise<{
1039
+ featureKey: string;
1040
+ entityType: string;
1041
+ entityId: string;
1042
+ role: string;
1043
+ id: string;
1044
+ appKey: string;
1045
+ createdAt: string;
1046
+ }>;
1047
+ byEntity: (entityType: string, entityId: string, featureKey?: string) => Promise<{
1048
+ reference: FileReferenceDto;
1049
+ file: FileAssetDto;
1050
+ }[]>;
1051
+ };
1052
+ folders: {
1053
+ get: (id?: string) => Promise<{
1054
+ folder: {
1055
+ id: string;
1056
+ name: string;
1057
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1058
+ ownerType: "USER" | "APP";
1059
+ ownerId: string;
1060
+ parentId: string | null;
1061
+ path: string;
1062
+ depth: number;
1063
+ status: "ACTIVE" | "TRASHED";
1064
+ createdAt: string;
1065
+ updatedAt: string;
1066
+ sourceId?: string | null | undefined;
1067
+ externalId?: string | null | undefined;
1068
+ };
1069
+ access: "view" | "owner" | "edit";
1070
+ breadcrumb: {
1071
+ id: string;
1072
+ name: string;
1073
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1074
+ }[];
1075
+ children: {
1076
+ id: string;
1077
+ name: string;
1078
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1079
+ ownerType: "USER" | "APP";
1080
+ ownerId: string;
1081
+ parentId: string | null;
1082
+ path: string;
1083
+ depth: number;
1084
+ status: "ACTIVE" | "TRASHED";
1085
+ createdAt: string;
1086
+ updatedAt: string;
1087
+ sourceId?: string | null | undefined;
1088
+ externalId?: string | null | undefined;
1089
+ }[];
1090
+ }>;
1091
+ tree: (root?: string, depth?: number) => Promise<unknown>;
1092
+ create: (input: CreateFolderInput) => Promise<{
1093
+ id: string;
1094
+ name: string;
1095
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1096
+ ownerType: "USER" | "APP";
1097
+ ownerId: string;
1098
+ parentId: string | null;
1099
+ path: string;
1100
+ depth: number;
1101
+ status: "ACTIVE" | "TRASHED";
1102
+ createdAt: string;
1103
+ updatedAt: string;
1104
+ sourceId?: string | null | undefined;
1105
+ externalId?: string | null | undefined;
1106
+ }>;
1107
+ update: (id: string, patch: UpdateFolderInput) => Promise<{
1108
+ id: string;
1109
+ name: string;
1110
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1111
+ ownerType: "USER" | "APP";
1112
+ ownerId: string;
1113
+ parentId: string | null;
1114
+ path: string;
1115
+ depth: number;
1116
+ status: "ACTIVE" | "TRASHED";
1117
+ createdAt: string;
1118
+ updatedAt: string;
1119
+ sourceId?: string | null | undefined;
1120
+ externalId?: string | null | undefined;
1121
+ }>;
1122
+ trash: (id: string) => Promise<{
1123
+ ok: true;
1124
+ }>;
1125
+ restore: (id: string) => Promise<{
1126
+ id: string;
1127
+ name: string;
1128
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1129
+ ownerType: "USER" | "APP";
1130
+ ownerId: string;
1131
+ parentId: string | null;
1132
+ path: string;
1133
+ depth: number;
1134
+ status: "ACTIVE" | "TRASHED";
1135
+ createdAt: string;
1136
+ updatedAt: string;
1137
+ sourceId?: string | null | undefined;
1138
+ externalId?: string | null | undefined;
1139
+ }>;
1140
+ /** ไฟล์ + โฟลเดอร์ใต้โฟลเดอร์ (recursive) พร้อม relativePath/md5/modifiedTime/providerFileId — ใช้ทำ fingerprint */
1141
+ contents: (id: string, opts?: {
1142
+ recursive?: boolean;
1143
+ }) => Promise<{
1144
+ folderId: string;
1145
+ sourceId: string | null;
1146
+ items: {
1147
+ id: string;
1148
+ isFolder: boolean;
1149
+ name: string;
1150
+ relativePath: string;
1151
+ parentId: string | null;
1152
+ mimeType: string | null;
1153
+ sizeBytes: string | null;
1154
+ md5: string | null;
1155
+ modifiedTime: string | null;
1156
+ providerFileId: string | null;
1157
+ webViewLink: string | null;
1158
+ status: string;
1159
+ }[];
1160
+ }>;
1161
+ /** หา/สร้างโฟลเดอร์ตามชื่อ (ใต้ linked source = สร้างใน Google Drive จริง) */
1162
+ ensurePath: (id: string, names: string[]) => Promise<{
1163
+ id: string;
1164
+ name: string;
1165
+ kind: "USER_ROOT" | "APP_ROOT" | "NORMAL";
1166
+ ownerType: "USER" | "APP";
1167
+ ownerId: string;
1168
+ parentId: string | null;
1169
+ path: string;
1170
+ depth: number;
1171
+ status: "ACTIVE" | "TRASHED";
1172
+ createdAt: string;
1173
+ updatedAt: string;
1174
+ sourceId?: string | null | undefined;
1175
+ externalId?: string | null | undefined;
1176
+ }>;
1177
+ };
1178
+ sources: {
1179
+ /** ผูก (idempotent — ผูกซ้ำ = source เดิม) แล้ว sync ทั้งต้นทันที */
1180
+ link: (input: LinkSourceInput) => Promise<{
1181
+ id: string;
1182
+ appKey: string;
1183
+ bucketKey: string;
1184
+ folderId: string;
1185
+ externalFolderId: string;
1186
+ sourceUrl: string;
1187
+ label: string | null;
1188
+ status: "ACTIVE" | "ERROR" | "PAUSED";
1189
+ lastSyncedAt: string | null;
1190
+ lastError: string | null;
1191
+ createdAt: string;
1192
+ stats?: {
1193
+ folders: number;
1194
+ files: number;
1195
+ created: number;
1196
+ updated: number;
1197
+ removed: number;
1198
+ } | undefined;
1199
+ }>;
1200
+ list: () => Promise<{
1201
+ id: string;
1202
+ appKey: string;
1203
+ bucketKey: string;
1204
+ folderId: string;
1205
+ externalFolderId: string;
1206
+ sourceUrl: string;
1207
+ label: string | null;
1208
+ status: "ACTIVE" | "ERROR" | "PAUSED";
1209
+ lastSyncedAt: string | null;
1210
+ lastError: string | null;
1211
+ createdAt: string;
1212
+ stats?: {
1213
+ folders: number;
1214
+ files: number;
1215
+ created: number;
1216
+ updated: number;
1217
+ removed: number;
1218
+ } | undefined;
1219
+ }[]>;
1220
+ get: (id: string) => Promise<{
1221
+ id: string;
1222
+ appKey: string;
1223
+ bucketKey: string;
1224
+ folderId: string;
1225
+ externalFolderId: string;
1226
+ sourceUrl: string;
1227
+ label: string | null;
1228
+ status: "ACTIVE" | "ERROR" | "PAUSED";
1229
+ lastSyncedAt: string | null;
1230
+ lastError: string | null;
1231
+ createdAt: string;
1232
+ stats?: {
1233
+ folders: number;
1234
+ files: number;
1235
+ created: number;
1236
+ updated: number;
1237
+ removed: number;
1238
+ } | undefined;
1239
+ }>;
1240
+ /** sync ทั้งต้นตอนนี้ (ปกติ Pi Files ตามการเปลี่ยนแปลงใน Drive ให้ทุก 5 นาที + webhook) */
1241
+ sync: (id: string) => Promise<{
1242
+ id: string;
1243
+ appKey: string;
1244
+ bucketKey: string;
1245
+ folderId: string;
1246
+ externalFolderId: string;
1247
+ sourceUrl: string;
1248
+ label: string | null;
1249
+ status: "ACTIVE" | "ERROR" | "PAUSED";
1250
+ lastSyncedAt: string | null;
1251
+ lastError: string | null;
1252
+ createdAt: string;
1253
+ stats?: {
1254
+ folders: number;
1255
+ files: number;
1256
+ created: number;
1257
+ updated: number;
1258
+ removed: number;
1259
+ } | undefined;
1260
+ }>;
1261
+ /** เลิกผูก — ไม่แตะ Google Drive; ไฟล์ที่ยังมี reference = 409 SOURCE_REFERENCED */
1262
+ unlink: (id: string) => Promise<{
1263
+ ok: true;
1264
+ files: number;
1265
+ folders: number;
1266
+ }>;
1267
+ };
1268
+ quota: {
1269
+ get: (scope?: "user" | "app" | "tenant") => Promise<{
1270
+ scope: "app" | "tenant" | "user";
1271
+ scopeId: string;
1272
+ bytesUsed: string;
1273
+ fileCount: number;
1274
+ quotaBytes: string | null;
1275
+ }>;
1276
+ };
1277
+ manifest: {
1278
+ sync: (input: FilesManifest) => Promise<{
1279
+ created: string[];
1280
+ updated: string[];
1281
+ deprecated: string[];
1282
+ }>;
1283
+ };
1284
+ migration: {
1285
+ /** รับ object ที่มีอยู่แล้วใน bucket เข้าทะเบียน ณ ที่เดิม (ไม่คัดลอก) — idempotent ด้วย externalSource+externalId */
1286
+ adopt: (input: AdoptFileInput) => Promise<{
1287
+ status: "created" | "existing";
1288
+ fileId: string;
1289
+ }>;
1290
+ };
1291
+ withUser: /*elided*/ any;
1292
+ };
1293
+ };
1294
+ type PiFilesClient = ReturnType<typeof createPiFiles>;
1295
+
1296
+ export { HttpOptions, PerformUploadOptions, UploadApi, UploadSource, createPiFiles };
1297
+ export type { PiFilesClient, PiFilesOptions };