@zergai/zergbox-client 0.1.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/index.d.ts ADDED
@@ -0,0 +1,211 @@
1
+ export type SyncNodeType = 'directory' | 'file'
2
+
3
+ export interface SyncNode {
4
+ id: string
5
+ path: string
6
+ type: SyncNodeType
7
+ revision?: number
8
+ contentHash?: string
9
+ sizeBytes?: number
10
+ updatedAt?: string
11
+ }
12
+
13
+ export type SyncChangeType =
14
+ | 'create_remote_folder'
15
+ | 'move_remote_folder'
16
+ | 'upload_file'
17
+ | 'move_remote_file'
18
+ | 'create_local_folder'
19
+ | 'move_local_folder'
20
+ | 'download_file'
21
+ | 'move_local_file'
22
+ | 'conflict'
23
+ | 'delete_remote'
24
+ | 'delete_remote_folder'
25
+ | 'delete_local'
26
+ | 'delete_local_folder'
27
+
28
+ export interface SyncChange {
29
+ type: SyncChangeType
30
+ path: string
31
+ fromPath?: string
32
+ reason?: string
33
+ remoteId?: string
34
+ }
35
+
36
+ export type MergeCandidateState = 'pending' | 'resolved' | 'dismissed'
37
+
38
+ export interface MergeCandidate {
39
+ id: string
40
+ path: string
41
+ state: MergeCandidateState
42
+ base?: SyncNode
43
+ local: SyncNode
44
+ remote: SyncNode
45
+ createdAt?: string
46
+ }
47
+
48
+ export const SYNC_NODE_TYPES: readonly SyncNodeType[]
49
+ export const SYNC_CHANGE_TYPES: readonly SyncChangeType[]
50
+ export const MERGE_CANDIDATE_STATES: readonly MergeCandidateState[]
51
+
52
+ export function isSyncNode(value: unknown): value is SyncNode
53
+ export function isSyncChange(value: unknown): value is SyncChange
54
+ export function isMergeCandidate(value: unknown): value is MergeCandidate
55
+
56
+ export interface ZergBoxClientOptions {
57
+ baseUrl: string
58
+ token: string
59
+ requestTimeoutMs?: number
60
+ maxResponseBytes?: number
61
+ maxDownloadBytes?: number
62
+ }
63
+
64
+ export interface ZergBoxOrganization {
65
+ id: string
66
+ name: string
67
+ slug?: string
68
+ }
69
+
70
+ export interface ZergBoxFolder {
71
+ id: string
72
+ name: string
73
+ parent_folder_id?: string | null
74
+ revision: number
75
+ updated_at?: string
76
+ }
77
+
78
+ export interface ZergBoxFile {
79
+ id: string
80
+ name: string
81
+ folder_id?: string
82
+ mime_type?: string
83
+ size_bytes?: number
84
+ current_version?: number
85
+ content_sha256: string
86
+ revision: number
87
+ updated_at?: string
88
+ }
89
+
90
+ export interface ZergBoxFolderListing {
91
+ folder: ZergBoxFolder
92
+ folders: ZergBoxFolder[]
93
+ files: ZergBoxFile[]
94
+ breadcrumbs?: ZergBoxFolder[]
95
+ }
96
+
97
+ export interface ZergBoxMutationResult {
98
+ id?: string
99
+ folder?: ZergBoxFolder
100
+ file?: ZergBoxFile
101
+ version?: number
102
+ }
103
+
104
+ export type ZergBoxChangeKind = 'created' | 'content' | 'moved' | 'deleted' | 'restored'
105
+
106
+ export interface ZergBoxContentChange {
107
+ cursor: number
108
+ entry_id: string
109
+ entry_kind: 'file' | 'folder'
110
+ change_kind: ZergBoxChangeKind
111
+ entry_name: string
112
+ parent_folder_id: string | null
113
+ previous_parent_folder_id: string | null
114
+ revision: number
115
+ content_sha256: string | null
116
+ created_at: string
117
+ }
118
+
119
+ export interface ZergBoxChangePage {
120
+ rootFolderId: string
121
+ changes: ZergBoxContentChange[]
122
+ nextCursor: number
123
+ hasMore: boolean
124
+ }
125
+
126
+ export interface ZergBoxByteUpload {
127
+ orgId: string
128
+ folderId: string
129
+ filename: string
130
+ bytes: Uint8Array
131
+ mediaType?: string
132
+ expectedAbsent?: true
133
+ }
134
+
135
+ export interface ZergBoxSyncClient {
136
+ getRootFolder(organizationId: string, options?: { limit?: number; offset?: number }): Promise<ZergBoxFolderListing>
137
+ getFolder(folderId: string, options?: { limit?: number; offset?: number }): Promise<ZergBoxFolderListing>
138
+ listChanges(rootFolderId: string, options?: { cursor?: number; limit?: number }): Promise<ZergBoxChangePage>
139
+ getChanges(input: { rootFolderId: string; cursor?: number; limit?: number }): Promise<ZergBoxChangePage>
140
+ createFolder(input: { orgId: string; parentFolderId: string; name: string; expectedAbsent?: true }): Promise<ZergBoxMutationResult>
141
+ updateFolder(input: { folderId: string; name?: string; parentFolderId?: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
142
+ uploadBytes(input: ZergBoxByteUpload): Promise<ZergBoxMutationResult>
143
+ uploadFile(input: { orgId: string; folderId: string; filePath: string; filename?: string; replaceExisting?: boolean }): Promise<ZergBoxMutationResult>
144
+ updateFileBytes(input: { fileId: string; filename?: string; bytes: Uint8Array; mediaType?: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
145
+ updateFileContent(input: { fileId: string; filePath: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
146
+ updateFile(input: { fileId: string; name?: string; folderId?: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
147
+ downloadFile(fileId: string, options?: { maxBytes?: number }): Promise<Uint8Array>
148
+ deleteRemoteFile(fileId: string, options: { expectedRevision: number }): Promise<unknown>
149
+ deleteRemoteFolder(folderId: string, options: { expectedRevision: number }): Promise<unknown>
150
+ }
151
+
152
+ export interface RemoteTree {
153
+ rootFolder: ZergBoxFolder
154
+ entries: SyncNode[]
155
+ }
156
+
157
+ export interface ZergBoxApiErrorDetails {
158
+ status?: number
159
+ body?: string
160
+ }
161
+
162
+ export interface ZergBoxSyncConflictDetails extends ZergBoxApiErrorDetails {
163
+ resourceType: 'file' | 'folder'
164
+ resourceId: string | null
165
+ resourcePath?: string
166
+ expectedRevision?: number
167
+ expectedAbsent?: true
168
+ }
169
+
170
+ export class ZergBoxApiError extends Error {
171
+ constructor(message: string, details?: ZergBoxApiErrorDetails)
172
+ status?: number
173
+ body?: string
174
+ }
175
+
176
+ export class ZergBoxSyncConflictError extends ZergBoxApiError {
177
+ constructor(message: string, details: ZergBoxSyncConflictDetails)
178
+ code: 'SYNC_CONFLICT'
179
+ recoverable: true
180
+ resourceType: 'file' | 'folder'
181
+ resourceId: string | null
182
+ resourcePath?: string
183
+ expectedRevision?: number
184
+ expectedAbsent?: true
185
+ }
186
+
187
+ export class ZergBoxClient implements ZergBoxSyncClient {
188
+ constructor(options: ZergBoxClientOptions)
189
+ listOrganizations(): Promise<ZergBoxOrganization[]>
190
+ getRootFolder(organizationId: string, options?: { limit?: number; offset?: number }): Promise<ZergBoxFolderListing>
191
+ getFolder(folderId: string, options?: { limit?: number; offset?: number }): Promise<ZergBoxFolderListing>
192
+ listChanges(rootFolderId: string, options?: { cursor?: number; limit?: number }): Promise<ZergBoxChangePage>
193
+ getChanges(input: { rootFolderId: string; cursor?: number; limit?: number }): Promise<ZergBoxChangePage>
194
+ createFolder(input: { orgId: string; parentFolderId: string; name: string; expectedAbsent?: true }): Promise<ZergBoxMutationResult>
195
+ updateFolder(input: { folderId: string; name?: string; parentFolderId?: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
196
+ uploadBytes(input: ZergBoxByteUpload): Promise<ZergBoxMutationResult>
197
+ uploadFile(input: { orgId: string; folderId: string; filePath: string; filename?: string; replaceExisting?: boolean }): Promise<ZergBoxMutationResult>
198
+ updateFileBytes(input: { fileId: string; filename?: string; bytes: Uint8Array; mediaType?: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
199
+ updateFileContent(input: { fileId: string; filePath: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
200
+ updateFile(input: { fileId: string; name?: string; folderId?: string; expectedRevision: number }): Promise<ZergBoxMutationResult>
201
+ downloadFile(fileId: string, options?: { maxBytes?: number }): Promise<Uint8Array>
202
+ deleteRemoteFile(fileId: string, options: { expectedRevision: number }): Promise<unknown>
203
+ deleteRemoteFolder(folderId: string, options: { expectedRevision: number }): Promise<unknown>
204
+ }
205
+
206
+ export function fetchRemoteTree(
207
+ client: Pick<ZergBoxSyncClient, 'getRootFolder' | 'getFolder'>,
208
+ options: { orgId: string; rootFolderId?: string; pageSize?: number }
209
+ ): Promise<RemoteTree>
210
+
211
+ export function remoteFileFingerprint(file: Partial<ZergBoxFile>): string
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@zergai/zergbox-client",
3
+ "version": "0.1.0",
4
+ "description": "Typed ZergBox API and bounded local sync client",
5
+ "type": "module",
6
+ "private": false,
7
+ "sideEffects": false,
8
+ "types": "./index.d.ts",
9
+ "packageManager": "npm@11.5.1",
10
+ "engines": {
11
+ "node": ">=22.19.0 <25",
12
+ "npm": ">=10.9.2 <12"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./sync": {
20
+ "types": "./sync.d.ts",
21
+ "import": "./dist/sync.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "index.d.ts",
27
+ "sync.d.ts",
28
+ "README.md"
29
+ ],
30
+ "scripts": {
31
+ "build": "node ./scripts/build.mjs",
32
+ "prepack": "npm run build"
33
+ },
34
+ "devDependencies": {
35
+ "esbuild": "0.27.3"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "provenance": false
40
+ },
41
+ "license": "UNLICENSED",
42
+ "homepage": "https://zergbox.com",
43
+ "bugs": {
44
+ "url": "https://github.com/Epoch-ML/zerg/issues"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/Epoch-ML/zerg.git",
49
+ "directory": "zapps/zergbox/client"
50
+ },
51
+ "keywords": [
52
+ "zergbox",
53
+ "file-sync",
54
+ "knowledge-base"
55
+ ]
56
+ }
package/sync.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ import type { SyncChange, ZergBoxSyncClient } from './index.js'
2
+
3
+ export * from './index.js'
4
+
5
+ export type TokenProvider = () => Promise<string | { token: string }> | string | { token: string }
6
+
7
+ export interface CreateSyncSessionOptions {
8
+ client?: ZergBoxSyncClient
9
+ baseUrl?: string
10
+ tokenProvider?: TokenProvider
11
+ organizationId: string
12
+ rootFolderId: string
13
+ localRoot: string
14
+ statePath?: string
15
+ deviceId: string
16
+ intervalMs?: number
17
+ debounceMs?: number
18
+ requestTimeoutMs?: number
19
+ afterSync?: (result: SyncResult) => Promise<void> | void
20
+ onError?: (error: Error) => void
21
+ }
22
+
23
+ export interface SyncResult {
24
+ actions: SyncChange[]
25
+ localRoot: string
26
+ statePath: string
27
+ syncedAt: string | null
28
+ paused: boolean
29
+ locked: boolean
30
+ }
31
+
32
+ export interface SyncStatus {
33
+ state: string
34
+ paused: boolean
35
+ watching: boolean
36
+ closed: boolean
37
+ deviceId: string
38
+ organizationId: string
39
+ rootFolderId: string
40
+ localRoot: string
41
+ statePath: string
42
+ lastSyncedAt: string | null
43
+ actionCount: number | null
44
+ conflictCount: number | null
45
+ errorMessage: string | null
46
+ }
47
+
48
+ export interface SyncSession {
49
+ syncOnce(options?: { force?: boolean }): Promise<SyncResult>
50
+ watch(options?: { immediate?: boolean }): Promise<SyncStatus>
51
+ status(): Promise<SyncStatus>
52
+ pause(reason?: string): Promise<SyncStatus>
53
+ resume(): Promise<SyncStatus>
54
+ stopWatching(): Promise<SyncStatus>
55
+ close(): Promise<SyncStatus>
56
+ }
57
+
58
+ export function createSyncSession(options: CreateSyncSessionOptions): SyncSession