@ultrst-armada/kloks 1.7.0 → 1.8.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/.krusbl-release-attestation.json +3 -3
- package/package.json +1 -1
- package/packages/backend/dist/{BaseStorageAdapter-tosOoSUg.d.ts → BaseStorageAdapter-EUCSvJse.d.ts} +7 -1
- package/packages/backend/dist/auth/index.d.ts +51 -13
- package/packages/backend/dist/auth/index.js +6 -2
- package/packages/backend/dist/{chunk-BI5RDDB4.js → chunk-3IUA66RS.js} +9 -2
- package/packages/backend/dist/{chunk-KSZ67VZJ.js → chunk-5RXXC6GE.js} +3 -3
- package/packages/backend/dist/{chunk-Y3X3H2XX.js → chunk-BPFZCDS4.js} +12 -12
- package/packages/backend/dist/{chunk-6QTNNZSE.js → chunk-BTMIK44G.js} +136 -71
- package/packages/backend/dist/{chunk-MPYASJ5A.js → chunk-HT2SEDHD.js} +1 -1
- package/packages/backend/dist/chunk-KKRWZDMN.js +237 -0
- package/packages/backend/dist/chunk-M4GSR46Y.js +205 -0
- package/packages/backend/dist/chunk-RBQ4CW3T.js +136 -0
- package/packages/backend/dist/{chunk-J2J24JVC.js → chunk-SHZAQTIT.js} +31 -204
- package/packages/backend/dist/{chunk-N4Z57FVR.js → chunk-XHADDA75.js} +9 -3
- package/packages/backend/dist/index.d.ts +5 -5
- package/packages/backend/dist/index.js +65 -50
- package/packages/backend/dist/krnl-services.js +7 -6
- package/packages/backend/dist/services/index.js +3 -2
- package/packages/backend/dist/srkl/index.d.ts +7 -1
- package/packages/backend/dist/srkl/index.js +3 -3
- package/packages/backend/dist/storage/index.d.ts +35 -3
- package/packages/backend/dist/storage/index.js +21 -10
- package/packages/backend/dist/workspace/index.d.ts +27 -33
- package/packages/backend/dist/workspace/index.js +2 -1
- package/packages/client/dist/index.d.ts +34 -1
- package/packages/client/dist/index.js +116 -0
- package/packages/backend/dist/chunk-LS3HWJBX.js +0 -0
- package/packages/backend/dist/chunk-ZDH4XI7W.js +0 -140
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"packageName": "@ultrst-armada/kloks",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"sourceCommit": "
|
|
4
|
+
"version": "1.8.0",
|
|
5
|
+
"sourceCommit": "d364f4fd5a705bea93c4fb0a93ff9740c1050f49",
|
|
6
6
|
"releaseWorkflow": "npm Release",
|
|
7
|
-
"workflowRunId": "
|
|
7
|
+
"workflowRunId": "40208606705"
|
|
8
8
|
}
|
package/package.json
CHANGED
package/packages/backend/dist/{BaseStorageAdapter-tosOoSUg.d.ts → BaseStorageAdapter-EUCSvJse.d.ts}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SkipoBase } from '@ultrst-armada/kloks/functions';
|
|
2
2
|
|
|
3
3
|
type StorageMode = 'local' | 'local_hosted' | 'remote';
|
|
4
|
-
type StorageProviderType = 'local_fs' | '
|
|
4
|
+
type StorageProviderType = 'local_fs' | 'backblaze_b2' | 'b2' | 'supabase' | 'firebase' | 'google_drive';
|
|
5
5
|
interface StorageConfig {
|
|
6
6
|
provider: StorageProviderType;
|
|
7
7
|
mode?: StorageMode;
|
|
@@ -19,6 +19,12 @@ interface StorageConfig {
|
|
|
19
19
|
keyId?: string;
|
|
20
20
|
applicationKey?: string;
|
|
21
21
|
accountId?: string;
|
|
22
|
+
googleClientId?: string;
|
|
23
|
+
googleRedirectUri?: string;
|
|
24
|
+
googleAccessToken?: string;
|
|
25
|
+
googleAccessTokenExpiresAt?: number;
|
|
26
|
+
googleRefreshToken?: string;
|
|
27
|
+
googleRootFolderId?: string;
|
|
22
28
|
}
|
|
23
29
|
interface FileInfo {
|
|
24
30
|
path: string;
|
|
@@ -26,31 +26,69 @@ declare class AdminGuard extends SkipoBase {
|
|
|
26
26
|
static verifyUser(authHeaderOrToken: string | null | undefined, provider: BaseAccountProvider): Promise<AuthSession>;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
* @file UnifiedAuthCore.ts
|
|
31
|
-
* @description Strict Universal Authentication against "ultrst-users" and "ultrst-credentials".
|
|
32
|
-
* Zero offline dummy fallbacks. Runs across Node.js, Vercel, and Cloudflare Workers (< 200 lines).
|
|
33
|
-
*/
|
|
34
|
-
interface SystemUser {
|
|
29
|
+
interface CanonicalAuthUser {
|
|
35
30
|
id: string;
|
|
36
31
|
email: string;
|
|
37
|
-
username: string;
|
|
38
32
|
name: string;
|
|
33
|
+
username?: string;
|
|
34
|
+
role?: string;
|
|
35
|
+
status?: string;
|
|
36
|
+
appProfiles?: Record<string, unknown>;
|
|
37
|
+
emailVerified?: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface CanonicalAuthSession {
|
|
40
|
+
session: Record<string, unknown>;
|
|
41
|
+
user: CanonicalAuthUser;
|
|
42
|
+
}
|
|
43
|
+
interface CanonicalAuthClientOptions {
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
fetcher?: typeof fetch;
|
|
46
|
+
credentials?: RequestCredentials;
|
|
47
|
+
}
|
|
48
|
+
interface AuthResult {
|
|
49
|
+
success: boolean;
|
|
50
|
+
status: number;
|
|
51
|
+
user?: CanonicalAuthUser;
|
|
52
|
+
session?: Record<string, unknown>;
|
|
53
|
+
error?: string;
|
|
54
|
+
redirectUrl?: string;
|
|
55
|
+
}
|
|
56
|
+
declare class CanonicalAuthClient {
|
|
57
|
+
private readonly baseUrl;
|
|
58
|
+
private readonly fetcher;
|
|
59
|
+
private readonly credentials;
|
|
60
|
+
constructor(options: CanonicalAuthClientOptions);
|
|
61
|
+
private request;
|
|
62
|
+
signInEmail(email: string, password: string): Promise<AuthResult>;
|
|
63
|
+
signUpEmail(email: string, password: string, name: string): Promise<AuthResult>;
|
|
64
|
+
signInGoogle(callbackURL: string): Promise<AuthResult>;
|
|
65
|
+
requestGoogleDriveAccess(callbackURL?: string): Promise<AuthResult>;
|
|
66
|
+
getSession(cookie?: string): Promise<CanonicalAuthSession | null>;
|
|
67
|
+
signOut(): Promise<boolean>;
|
|
68
|
+
}
|
|
69
|
+
declare function createCanonicalAuthClient(baseUrl: string, fetcher?: typeof fetch): CanonicalAuthClient;
|
|
70
|
+
|
|
71
|
+
interface SystemUser extends CanonicalAuthUser {
|
|
72
|
+
username: string;
|
|
39
73
|
role: string;
|
|
40
74
|
status: string;
|
|
41
|
-
appProfiles?: Record<string,
|
|
75
|
+
appProfiles?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
interface AuthEnvironment {
|
|
78
|
+
SRKL_AUTH_BASE_URL?: string;
|
|
79
|
+
[key: string]: unknown;
|
|
42
80
|
}
|
|
43
|
-
declare function loginSystemUser(email: string, rawPass: string, isAdmin: boolean,
|
|
81
|
+
declare function loginSystemUser(email: string, rawPass: string, isAdmin: boolean, _queryDb: (sql: string, params?: unknown[]) => Promise<{
|
|
44
82
|
rows: any[];
|
|
45
|
-
}
|
|
83
|
+
}>, env?: AuthEnvironment): Promise<{
|
|
46
84
|
success: boolean;
|
|
47
85
|
status: number;
|
|
48
86
|
token?: string;
|
|
49
87
|
user?: SystemUser;
|
|
50
88
|
error?: string;
|
|
51
89
|
}>;
|
|
52
|
-
declare function resolveUserFromToken(tokenOrUserId: string,
|
|
90
|
+
declare function resolveUserFromToken(tokenOrUserId: string, _queryDb: (sql: string, params?: unknown[]) => Promise<{
|
|
53
91
|
rows: any[];
|
|
54
|
-
}
|
|
92
|
+
}>, env?: AuthEnvironment): Promise<SystemUser | null>;
|
|
55
93
|
|
|
56
|
-
export { AdminGuard, AuthSession, BaseAccountProvider, CreateUserData, LocalAccountProvider, PasswordHasher, type SystemUser, User, loginSystemUser, resolveUserFromToken };
|
|
94
|
+
export { AdminGuard, type AuthEnvironment, type AuthResult, AuthSession, BaseAccountProvider, CanonicalAuthClient, type CanonicalAuthClientOptions, type CanonicalAuthSession, type CanonicalAuthUser, CreateUserData, LocalAccountProvider, PasswordHasher, type SystemUser, User, createCanonicalAuthClient, loginSystemUser, resolveUserFromToken };
|
|
@@ -3,20 +3,24 @@ import {
|
|
|
3
3
|
BaseAccountProvider,
|
|
4
4
|
LocalAccountProvider,
|
|
5
5
|
PasswordHasher
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-HT2SEDHD.js";
|
|
7
7
|
import {
|
|
8
|
+
CanonicalAuthClient,
|
|
8
9
|
RateLimiter,
|
|
9
10
|
SessionManager,
|
|
11
|
+
createCanonicalAuthClient,
|
|
10
12
|
loginSystemUser,
|
|
11
13
|
resolveUserFromToken
|
|
12
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-M4GSR46Y.js";
|
|
13
15
|
export {
|
|
14
16
|
AdminGuard,
|
|
15
17
|
BaseAccountProvider,
|
|
18
|
+
CanonicalAuthClient,
|
|
16
19
|
LocalAccountProvider,
|
|
17
20
|
PasswordHasher,
|
|
18
21
|
RateLimiter,
|
|
19
22
|
SessionManager,
|
|
23
|
+
createCanonicalAuthClient,
|
|
20
24
|
loginSystemUser,
|
|
21
25
|
resolveUserFromToken
|
|
22
26
|
};
|
|
@@ -121,9 +121,10 @@ var SrklClient = class {
|
|
|
121
121
|
const creds = account.credentials || {};
|
|
122
122
|
const sId = (account.serviceId || "").toLowerCase();
|
|
123
123
|
const isB2 = sId.includes("backblaze") || sId === "b2";
|
|
124
|
+
const isGoogle = sId.includes("google_drive") || sId.includes("googledrive") || sId === "google";
|
|
124
125
|
return {
|
|
125
126
|
id: `conn-srkl-${account.id}`,
|
|
126
|
-
provider: isB2 ? "backblaze_b2" : "aws_s3",
|
|
127
|
+
provider: isB2 ? "backblaze_b2" : isGoogle ? "google_drive" : "aws_s3",
|
|
127
128
|
label: `SRKL: ${account.name || (isB2 ? "Backblaze" : "S3")}`,
|
|
128
129
|
role: "redundant_clone",
|
|
129
130
|
enabled: true,
|
|
@@ -137,7 +138,13 @@ var SrklClient = class {
|
|
|
137
138
|
s3SecretAccessKey: creds.secretAccessKey || creds.applicationKey || creds.s3SecretAccessKey,
|
|
138
139
|
s3BucketName: creds.bucketName || creds.s3BucketName,
|
|
139
140
|
s3Region: creds.region || creds.s3Region,
|
|
140
|
-
s3Endpoint: creds.endpoint || creds.s3Endpoint
|
|
141
|
+
s3Endpoint: creds.endpoint || creds.s3Endpoint,
|
|
142
|
+
googleEmail: creds.email || account.credentials?.email || account.name,
|
|
143
|
+
googleRootFolderId: creds.rootFolderId,
|
|
144
|
+
googleRootFolderName: creds.rootFolderName,
|
|
145
|
+
googleAccessToken: creds.accessToken,
|
|
146
|
+
googleAccessTokenExpiresAt: creds.accessTokenExpiresAt,
|
|
147
|
+
googleRefreshToken: creds.refreshToken
|
|
141
148
|
};
|
|
142
149
|
}
|
|
143
150
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
StorageAdapterFactory
|
|
3
|
-
} from "./chunk-J2J24JVC.js";
|
|
4
1
|
import {
|
|
5
2
|
findUserWorkspace
|
|
6
3
|
} from "./chunk-6K75XXFD.js";
|
|
4
|
+
import {
|
|
5
|
+
StorageAdapterFactory
|
|
6
|
+
} from "./chunk-SHZAQTIT.js";
|
|
7
7
|
|
|
8
8
|
// src/services/workspaceGraphService.ts
|
|
9
9
|
function slugify(name) {
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
workspaceGraphService
|
|
3
|
-
} from "./chunk-KSZ67VZJ.js";
|
|
4
1
|
import {
|
|
5
2
|
getSrklAccounts,
|
|
6
3
|
srklListBackblazeBuckets
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import {
|
|
9
|
-
StorageAdapterFactory
|
|
10
|
-
} from "./chunk-J2J24JVC.js";
|
|
4
|
+
} from "./chunk-XHADDA75.js";
|
|
11
5
|
import {
|
|
12
|
-
|
|
13
|
-
} from "./chunk-
|
|
6
|
+
workspaceGraphService
|
|
7
|
+
} from "./chunk-5RXXC6GE.js";
|
|
14
8
|
import {
|
|
15
9
|
formatCanonicalWorkspaceFolderName,
|
|
16
10
|
sanitizeWorkspaceName
|
|
@@ -25,12 +19,18 @@ import {
|
|
|
25
19
|
import {
|
|
26
20
|
queryUnifiedDb
|
|
27
21
|
} from "./chunk-VAFCR2MS.js";
|
|
22
|
+
import {
|
|
23
|
+
b2ListBuckets
|
|
24
|
+
} from "./chunk-4QEMALXF.js";
|
|
25
|
+
import {
|
|
26
|
+
StorageAdapterFactory
|
|
27
|
+
} from "./chunk-SHZAQTIT.js";
|
|
28
28
|
import {
|
|
29
29
|
RateLimiter,
|
|
30
30
|
SessionManager,
|
|
31
31
|
loginSystemUser,
|
|
32
32
|
resolveUserFromToken
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-M4GSR46Y.js";
|
|
34
34
|
import {
|
|
35
35
|
createService,
|
|
36
36
|
createServiceDefinition
|
|
@@ -56,12 +56,12 @@ var AuthServiceDefinition = createServiceDefinition({
|
|
|
56
56
|
login: {
|
|
57
57
|
id: "AuthService.login",
|
|
58
58
|
name: "login",
|
|
59
|
-
handler: async (input) => loginSystemUser(input.email, input.password, Boolean(input.isAdmin), (sql, params) => queryUnifiedDb(sql, params, input.env))
|
|
59
|
+
handler: async (input) => loginSystemUser(input.email, input.password, Boolean(input.isAdmin), (sql, params) => queryUnifiedDb(sql, params, input.env), input.env)
|
|
60
60
|
},
|
|
61
61
|
resolveUser: {
|
|
62
62
|
id: "AuthService.resolveUser",
|
|
63
63
|
name: "resolveUser",
|
|
64
|
-
handler: async (input) => resolveUserFromToken(input.tokenOrUserId, (sql, params) => queryUnifiedDb(sql, params, input.env))
|
|
64
|
+
handler: async (input) => resolveUserFromToken(input.tokenOrUserId, (sql, params) => queryUnifiedDb(sql, params, input.env), input.env)
|
|
65
65
|
},
|
|
66
66
|
checkRateLimit: {
|
|
67
67
|
id: "AuthService.checkRateLimit",
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createWorkspace,
|
|
3
3
|
deleteWorkspace,
|
|
4
|
-
deleteWorkspaceFile,
|
|
5
4
|
findUserWorkspace,
|
|
6
5
|
getWorkspaces,
|
|
7
|
-
|
|
8
|
-
readWorkspaceFile,
|
|
9
|
-
updateWorkspace,
|
|
10
|
-
writeWorkspaceFile
|
|
6
|
+
updateWorkspace
|
|
11
7
|
} from "./chunk-6K75XXFD.js";
|
|
12
8
|
import {
|
|
13
9
|
b2DownloadFile,
|
|
@@ -15,6 +11,9 @@ import {
|
|
|
15
11
|
b2UploadFile,
|
|
16
12
|
queryUnifiedDb
|
|
17
13
|
} from "./chunk-VAFCR2MS.js";
|
|
14
|
+
import {
|
|
15
|
+
GoogleDriveAdapter
|
|
16
|
+
} from "./chunk-KKRWZDMN.js";
|
|
18
17
|
|
|
19
18
|
// src/workspace/WorkspaceFS.ts
|
|
20
19
|
import { SkipoBase } from "@ultrst-armada/kloks/functions";
|
|
@@ -135,58 +134,6 @@ var WorkspaceCloneSyncEngine = class extends SkipoBase3 {
|
|
|
135
134
|
}
|
|
136
135
|
};
|
|
137
136
|
|
|
138
|
-
// src/workspace/RemoteWorkspaceService.ts
|
|
139
|
-
var RemoteWorkspaceService = class {
|
|
140
|
-
type = "remote";
|
|
141
|
-
async findWorkspace(workspaceId, env) {
|
|
142
|
-
return await findUserWorkspace(workspaceId, env);
|
|
143
|
-
}
|
|
144
|
-
async listWorkspaces(userId, env) {
|
|
145
|
-
return await getWorkspaces(userId, env);
|
|
146
|
-
}
|
|
147
|
-
async createWorkspace(userId, data, env) {
|
|
148
|
-
return await createWorkspace(userId, data, env);
|
|
149
|
-
}
|
|
150
|
-
async updateWorkspace(userId, params, env) {
|
|
151
|
-
return await updateWorkspace(userId, params, env);
|
|
152
|
-
}
|
|
153
|
-
async deleteWorkspace(userId, workspaceId, env) {
|
|
154
|
-
return await deleteWorkspace(userId, workspaceId, env);
|
|
155
|
-
}
|
|
156
|
-
async readFile(workspaceId, filePath, env) {
|
|
157
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
158
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
159
|
-
const data = await readWorkspaceFile(workspace, connection, filePath);
|
|
160
|
-
if (!data) throw new Error(`File "${filePath}" not found in workspace "${workspaceId}".`);
|
|
161
|
-
return data;
|
|
162
|
-
}
|
|
163
|
-
async writeFile(workspaceId, filePath, content, env) {
|
|
164
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
165
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
166
|
-
await writeWorkspaceFile(workspace, connection, filePath, content);
|
|
167
|
-
const size = typeof content === "string" ? new TextEncoder().encode(content).length : content.byteLength;
|
|
168
|
-
return { success: true, path: filePath, sizeBytes: size };
|
|
169
|
-
}
|
|
170
|
-
async deleteFile(workspaceId, filePath, env) {
|
|
171
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
172
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
173
|
-
const deleted = await deleteWorkspaceFile(workspace, connection, filePath);
|
|
174
|
-
return { success: deleted };
|
|
175
|
-
}
|
|
176
|
-
async listFiles(workspaceId, subfolder = "", env) {
|
|
177
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
178
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
179
|
-
const files = await listWorkspaceFiles(workspace, connection, subfolder);
|
|
180
|
-
return files.map((f) => ({
|
|
181
|
-
path: f.fileName,
|
|
182
|
-
name: f.fileName.split("/").pop() || f.fileName,
|
|
183
|
-
sizeBytes: f.sizeBytes,
|
|
184
|
-
updatedAt: f.uploadTimestamp
|
|
185
|
-
}));
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
var remoteWorkspaceService = new RemoteWorkspaceService();
|
|
189
|
-
|
|
190
137
|
// src/workspace/WorkingWorkspaceService.ts
|
|
191
138
|
import fs2 from "fs";
|
|
192
139
|
import path2 from "path";
|
|
@@ -245,8 +192,10 @@ function setWorkingWorkspaceConfig(cfg) {
|
|
|
245
192
|
}
|
|
246
193
|
return updated;
|
|
247
194
|
}
|
|
248
|
-
function getWorkingWorkspaceDir() {
|
|
249
|
-
const
|
|
195
|
+
function getWorkingWorkspaceDir(workspaceId = "default") {
|
|
196
|
+
const root = getWorkingWorkspaceConfig().workingDirectory;
|
|
197
|
+
const safeId = workspaceId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
198
|
+
const dir = path.join(root, safeId);
|
|
250
199
|
if (!fs.existsSync(dir)) {
|
|
251
200
|
fs.mkdirSync(dir, { recursive: true });
|
|
252
201
|
}
|
|
@@ -331,7 +280,7 @@ async function syncWorkspace(workspaceId) {
|
|
|
331
280
|
}
|
|
332
281
|
const { workspace, user, connection } = match;
|
|
333
282
|
const folderKey = getWorkspaceFolderKey(workspace, user);
|
|
334
|
-
const workingDir = getWorkingWorkspaceDir();
|
|
283
|
+
const workingDir = getWorkingWorkspaceDir(workspaceId);
|
|
335
284
|
const isB2 = workspace.storageProvider === "backblaze_b2" || workspace.storageConfig?.type === "b2";
|
|
336
285
|
const syncedFiles = [];
|
|
337
286
|
let uploadedCount = 0;
|
|
@@ -428,6 +377,86 @@ async function syncWorkspace(workspaceId) {
|
|
|
428
377
|
};
|
|
429
378
|
}
|
|
430
379
|
}
|
|
380
|
+
const isGoogleDrive = workspace.storageProvider === "google_drive" || workspace.storageConfig?.type === "google_drive";
|
|
381
|
+
if (isGoogleDrive) {
|
|
382
|
+
const creds = workspace.storageConfig || connection?.credentials || connection || {};
|
|
383
|
+
const rootFolderId = creds.googleRootFolderId || creds.rootFolderId || workspace.googleRootFolderId;
|
|
384
|
+
const adapter = new GoogleDriveAdapter({
|
|
385
|
+
provider: "google_drive",
|
|
386
|
+
googleAccessToken: creds.googleAccessToken || creds.accessToken,
|
|
387
|
+
googleAccessTokenExpiresAt: creds.googleAccessTokenExpiresAt,
|
|
388
|
+
googleRefreshToken: creds.googleRefreshToken || creds.refreshToken,
|
|
389
|
+
googleClientId: creds.googleClientId || process.env.GOOGLE_CLIENT_ID,
|
|
390
|
+
googleRootFolderId: rootFolderId
|
|
391
|
+
});
|
|
392
|
+
try {
|
|
393
|
+
const remoteFiles = await adapter.list("");
|
|
394
|
+
const remoteMap = /* @__PURE__ */ new Map();
|
|
395
|
+
for (const rf of remoteFiles) {
|
|
396
|
+
if (rf.path) remoteMap.set(rf.path, { size: rf.size, timestamp: rf.modifiedAt });
|
|
397
|
+
}
|
|
398
|
+
const localFiles = await collectLocalFiles(workingDir);
|
|
399
|
+
const localMap = /* @__PURE__ */ new Map();
|
|
400
|
+
for (const lf of localFiles) {
|
|
401
|
+
localMap.set(lf.relPath, lf);
|
|
402
|
+
}
|
|
403
|
+
for (const [relPath, rInfo] of remoteMap.entries()) {
|
|
404
|
+
const lFile = localMap.get(relPath);
|
|
405
|
+
const shouldDownload = !lFile || rInfo.timestamp > lFile.mtimeMs + 2e3;
|
|
406
|
+
if (shouldDownload) {
|
|
407
|
+
const buf = await adapter.read(relPath);
|
|
408
|
+
const destPath = path.join(workingDir, relPath);
|
|
409
|
+
await fs.promises.mkdir(path.dirname(destPath), { recursive: true });
|
|
410
|
+
await fs.promises.writeFile(destPath, buf);
|
|
411
|
+
try {
|
|
412
|
+
const fileTime = new Date(rInfo.timestamp);
|
|
413
|
+
await fs.promises.utimes(destPath, fileTime, fileTime);
|
|
414
|
+
} catch {
|
|
415
|
+
}
|
|
416
|
+
syncedFiles.push({ fileName: relPath, action: "DOWNLOADED", sizeBytes: buf.byteLength });
|
|
417
|
+
downloadedCount++;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
for (const [relPath, lFile] of localMap.entries()) {
|
|
421
|
+
const rInfo = remoteMap.get(relPath);
|
|
422
|
+
const shouldUpload = !rInfo || lFile.mtimeMs > rInfo.timestamp + 2e3;
|
|
423
|
+
if (shouldUpload) {
|
|
424
|
+
const content = await fs.promises.readFile(lFile.fullPath);
|
|
425
|
+
await adapter.write(relPath, new Uint8Array(content));
|
|
426
|
+
syncedFiles.push({ fileName: relPath, action: "UPLOADED", sizeBytes: lFile.sizeBytes });
|
|
427
|
+
uploadedCount++;
|
|
428
|
+
} else if (!syncedFiles.some((f) => f.fileName === relPath)) {
|
|
429
|
+
syncedFiles.push({ fileName: relPath, action: "UP_TO_DATE", sizeBytes: lFile.sizeBytes });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
success: true,
|
|
434
|
+
workspaceId,
|
|
435
|
+
folderKey,
|
|
436
|
+
workingDir,
|
|
437
|
+
persistenceType: "google_drive",
|
|
438
|
+
targetLocation: `GoogleDrive://${rootFolderId || "root"}`,
|
|
439
|
+
syncedFiles,
|
|
440
|
+
uploadedCount,
|
|
441
|
+
downloadedCount,
|
|
442
|
+
syncedAt: nowIso
|
|
443
|
+
};
|
|
444
|
+
} catch (err) {
|
|
445
|
+
return {
|
|
446
|
+
success: false,
|
|
447
|
+
workspaceId,
|
|
448
|
+
folderKey,
|
|
449
|
+
workingDir,
|
|
450
|
+
persistenceType: "google_drive",
|
|
451
|
+
targetLocation: `GoogleDrive://${rootFolderId || "root"}`,
|
|
452
|
+
syncedFiles,
|
|
453
|
+
uploadedCount,
|
|
454
|
+
downloadedCount,
|
|
455
|
+
syncedAt: nowIso,
|
|
456
|
+
error: err.message || "Google Drive sync failed."
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
}
|
|
431
460
|
const vaultDir = path.resolve(process.cwd(), folderKey);
|
|
432
461
|
await fs.promises.mkdir(vaultDir, { recursive: true });
|
|
433
462
|
try {
|
|
@@ -505,8 +534,8 @@ var WorkingWorkspaceService = class {
|
|
|
505
534
|
}
|
|
506
535
|
workingDirResolver;
|
|
507
536
|
type = "working";
|
|
508
|
-
getWorkingDir() {
|
|
509
|
-
return this.workingDirResolver ? this.workingDirResolver() : getWorkingWorkspaceDir();
|
|
537
|
+
getWorkingDir(workspaceId) {
|
|
538
|
+
return this.workingDirResolver ? this.workingDirResolver(workspaceId) : getWorkingWorkspaceDir(workspaceId);
|
|
510
539
|
}
|
|
511
540
|
async findWorkspace(workspaceId, env) {
|
|
512
541
|
return await findUserWorkspace(workspaceId, env);
|
|
@@ -516,7 +545,7 @@ var WorkingWorkspaceService = class {
|
|
|
516
545
|
}
|
|
517
546
|
async createWorkspace(userId, data, env) {
|
|
518
547
|
const res = await createWorkspace(userId, data, env);
|
|
519
|
-
const dir = this.getWorkingDir();
|
|
548
|
+
const dir = this.getWorkingDir(res.workspace?.id || data?.id || "default");
|
|
520
549
|
try {
|
|
521
550
|
await fs2.promises.mkdir(dir, { recursive: true });
|
|
522
551
|
} catch {
|
|
@@ -531,12 +560,12 @@ var WorkingWorkspaceService = class {
|
|
|
531
560
|
}
|
|
532
561
|
async readFile(_workspaceId, filePath) {
|
|
533
562
|
const cleanRel = filePath.replace(/^\/+/, "");
|
|
534
|
-
const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
|
|
563
|
+
const fullPath = path2.resolve(this.getWorkingDir(_workspaceId), cleanRel);
|
|
535
564
|
return await fs2.promises.readFile(fullPath);
|
|
536
565
|
}
|
|
537
566
|
async writeFile(_workspaceId, filePath, content) {
|
|
538
567
|
const cleanRel = filePath.replace(/^\/+/, "");
|
|
539
|
-
const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
|
|
568
|
+
const fullPath = path2.resolve(this.getWorkingDir(_workspaceId), cleanRel);
|
|
540
569
|
await fs2.promises.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
541
570
|
const buffer = typeof content === "string" ? Buffer.from(content) : Buffer.from(content.buffer, content.byteOffset, content.byteLength);
|
|
542
571
|
await fs2.promises.writeFile(fullPath, buffer);
|
|
@@ -544,7 +573,7 @@ var WorkingWorkspaceService = class {
|
|
|
544
573
|
}
|
|
545
574
|
async deleteFile(_workspaceId, filePath) {
|
|
546
575
|
const cleanRel = filePath.replace(/^\/+/, "");
|
|
547
|
-
const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
|
|
576
|
+
const fullPath = path2.resolve(this.getWorkingDir(_workspaceId), cleanRel);
|
|
548
577
|
try {
|
|
549
578
|
await fs2.promises.unlink(fullPath);
|
|
550
579
|
return { success: true };
|
|
@@ -553,7 +582,7 @@ var WorkingWorkspaceService = class {
|
|
|
553
582
|
}
|
|
554
583
|
}
|
|
555
584
|
async listFiles(_workspaceId, subfolder = "") {
|
|
556
|
-
const baseDir = path2.resolve(this.getWorkingDir(), subfolder.replace(/^\/+/, ""));
|
|
585
|
+
const baseDir = path2.resolve(this.getWorkingDir(_workspaceId), subfolder.replace(/^\/+/, ""));
|
|
557
586
|
if (!fs2.existsSync(baseDir)) return [];
|
|
558
587
|
const entries = await fs2.promises.readdir(baseDir, { withFileTypes: true });
|
|
559
588
|
return entries.map((e) => {
|
|
@@ -567,7 +596,7 @@ var WorkingWorkspaceService = class {
|
|
|
567
596
|
} catch {
|
|
568
597
|
}
|
|
569
598
|
return {
|
|
570
|
-
path: path2.relative(this.getWorkingDir(), full),
|
|
599
|
+
path: path2.relative(this.getWorkingDir(_workspaceId), full),
|
|
571
600
|
name: e.name,
|
|
572
601
|
isFolder: e.isDirectory(),
|
|
573
602
|
sizeBytes,
|
|
@@ -581,12 +610,46 @@ var WorkingWorkspaceService = class {
|
|
|
581
610
|
};
|
|
582
611
|
var workingWorkspaceService = new WorkingWorkspaceService();
|
|
583
612
|
|
|
613
|
+
// src/workspace/RemoteWorkspaceService.ts
|
|
614
|
+
var RemoteWorkspaceService = class {
|
|
615
|
+
type = "working";
|
|
616
|
+
findWorkspace(id, env) {
|
|
617
|
+
return workingWorkspaceService.findWorkspace(id, env);
|
|
618
|
+
}
|
|
619
|
+
listWorkspaces(userId, env) {
|
|
620
|
+
return workingWorkspaceService.listWorkspaces(userId, env);
|
|
621
|
+
}
|
|
622
|
+
createWorkspace(userId, data, env) {
|
|
623
|
+
return workingWorkspaceService.createWorkspace(userId, data, env);
|
|
624
|
+
}
|
|
625
|
+
updateWorkspace(userId, params, env) {
|
|
626
|
+
return workingWorkspaceService.updateWorkspace(userId, params, env);
|
|
627
|
+
}
|
|
628
|
+
deleteWorkspace(userId, id, env) {
|
|
629
|
+
return workingWorkspaceService.deleteWorkspace(userId, id, env);
|
|
630
|
+
}
|
|
631
|
+
readFile(id, path3, env) {
|
|
632
|
+
return workingWorkspaceService.readFile(id, path3);
|
|
633
|
+
}
|
|
634
|
+
writeFile(id, path3, content, env) {
|
|
635
|
+
return workingWorkspaceService.writeFile(id, path3, content);
|
|
636
|
+
}
|
|
637
|
+
deleteFile(id, path3, env) {
|
|
638
|
+
return workingWorkspaceService.deleteFile(id, path3);
|
|
639
|
+
}
|
|
640
|
+
listFiles(id, subfolder, env) {
|
|
641
|
+
return workingWorkspaceService.listFiles(id, subfolder);
|
|
642
|
+
}
|
|
643
|
+
sync(id, options, env) {
|
|
644
|
+
return workingWorkspaceService.sync(id, options);
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
var remoteWorkspaceService = workingWorkspaceService;
|
|
648
|
+
|
|
584
649
|
export {
|
|
585
650
|
WorkspaceFS,
|
|
586
651
|
SyncEngine,
|
|
587
652
|
WorkspaceCloneSyncEngine,
|
|
588
|
-
RemoteWorkspaceService,
|
|
589
|
-
remoteWorkspaceService,
|
|
590
653
|
getDefaultWorkingWorkspaceDir,
|
|
591
654
|
getWorkingWorkspaceConfig,
|
|
592
655
|
setWorkingWorkspaceConfig,
|
|
@@ -595,5 +658,7 @@ export {
|
|
|
595
658
|
getWorkspaceFolderKey,
|
|
596
659
|
syncWorkspace,
|
|
597
660
|
WorkingWorkspaceService,
|
|
598
|
-
workingWorkspaceService
|
|
661
|
+
workingWorkspaceService,
|
|
662
|
+
RemoteWorkspaceService,
|
|
663
|
+
remoteWorkspaceService
|
|
599
664
|
};
|