mindsim 0.1.6 → 0.1.8
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/README.md +110 -2
- package/dist/cli.js +96 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +58 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +357 -13
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +60 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +131 -4
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +63 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +98 -0
- package/dist/logger.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +66 -18
- package/dist/version.js.map +1 -1
- package/package.json +2 -1
- package/src/cli.ts +106 -0
- package/src/config.ts +409 -17
- package/src/index.ts +177 -5
- package/src/logger.ts +111 -0
- package/src/types.ts +59 -0
- package/src/version.ts +78 -20
- package/tests/config.test.ts +465 -1
- package/tests/service-json.test.ts +567 -0
package/tests/config.test.ts
CHANGED
|
@@ -2,7 +2,15 @@ import fs from "node:fs";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, type Mocked, vi } from "vitest";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getApiBaseUrl,
|
|
7
|
+
getDeviceAuthConfig,
|
|
8
|
+
loadApiKey,
|
|
9
|
+
loadServiceJson,
|
|
10
|
+
loadServiceJsonFromBase64,
|
|
11
|
+
saveApiKey,
|
|
12
|
+
validateServiceJson,
|
|
13
|
+
} from "../src/config";
|
|
6
14
|
|
|
7
15
|
// Mock Node built-ins
|
|
8
16
|
vi.mock("node:fs");
|
|
@@ -130,5 +138,461 @@ describe("Config Module", () => {
|
|
|
130
138
|
vi.stubEnv("MIND_SIM_API_BASE_URL", "https://staging.api.mindsim.com");
|
|
131
139
|
expect(getApiBaseUrl()).toBe("https://staging.api.mindsim.com");
|
|
132
140
|
});
|
|
141
|
+
|
|
142
|
+
it("should prioritize MINDSIM_API_BASE_URL over deprecated MIND_SIM_API_BASE_URL", () => {
|
|
143
|
+
vi.stubEnv("MINDSIM_API_BASE_URL", "https://new-api.reasoner.com");
|
|
144
|
+
vi.stubEnv("MIND_SIM_API_BASE_URL", "https://old-api.reasoner.com");
|
|
145
|
+
expect(getApiBaseUrl()).toBe("https://new-api.reasoner.com");
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("validateServiceJson", () => {
|
|
150
|
+
// Valid service JSON fixture
|
|
151
|
+
const createValidServiceJson = (overrides?: Record<string, unknown>) => ({
|
|
152
|
+
type: "mindsim_service_account",
|
|
153
|
+
version: "1",
|
|
154
|
+
project_id: "my-app",
|
|
155
|
+
project_name: "My App",
|
|
156
|
+
environment: "production",
|
|
157
|
+
client_email: "service@my-app.mindsim.io",
|
|
158
|
+
client_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
159
|
+
api_key: "ms_prod_abc123xyz789",
|
|
160
|
+
api_base_url: "https://api.reasoner.com/api/mindsim",
|
|
161
|
+
scopes: ["minds:read", "simulate:run"],
|
|
162
|
+
app_metadata: {
|
|
163
|
+
app_id: "550e8400-e29b-41d4-a716-446655440001",
|
|
164
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440002",
|
|
165
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440003",
|
|
166
|
+
use_case: "internal-workflow",
|
|
167
|
+
},
|
|
168
|
+
created_at: "2025-12-21T00:00:00.000Z",
|
|
169
|
+
...overrides,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe("basic validation", () => {
|
|
173
|
+
it("should accept valid service JSON", () => {
|
|
174
|
+
const result = validateServiceJson(createValidServiceJson());
|
|
175
|
+
expect(result.valid).toBe(true);
|
|
176
|
+
expect(result.errors).toHaveLength(0);
|
|
177
|
+
expect(result.serviceJson).toBeDefined();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should reject non-object input", () => {
|
|
181
|
+
const result = validateServiceJson(null);
|
|
182
|
+
expect(result.valid).toBe(false);
|
|
183
|
+
expect(result.errors).toContain("Service JSON must be a valid object");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should reject undefined input", () => {
|
|
187
|
+
const result = validateServiceJson(undefined);
|
|
188
|
+
expect(result.valid).toBe(false);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should reject string input", () => {
|
|
192
|
+
const result = validateServiceJson("not an object");
|
|
193
|
+
expect(result.valid).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe("required fields validation", () => {
|
|
198
|
+
it("should require type field", () => {
|
|
199
|
+
const result = validateServiceJson(createValidServiceJson({ type: undefined }));
|
|
200
|
+
expect(result.valid).toBe(false);
|
|
201
|
+
expect(result.errors.some((e) => e.includes("type"))).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("should require version field", () => {
|
|
205
|
+
const result = validateServiceJson(createValidServiceJson({ version: undefined }));
|
|
206
|
+
expect(result.valid).toBe(false);
|
|
207
|
+
expect(result.errors.some((e) => e.includes("version"))).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should require project_id field", () => {
|
|
211
|
+
const result = validateServiceJson(createValidServiceJson({ project_id: undefined }));
|
|
212
|
+
expect(result.valid).toBe(false);
|
|
213
|
+
expect(result.errors.some((e) => e.includes("project_id"))).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("should require api_key field", () => {
|
|
217
|
+
const result = validateServiceJson(createValidServiceJson({ api_key: undefined }));
|
|
218
|
+
expect(result.valid).toBe(false);
|
|
219
|
+
expect(result.errors.some((e) => e.includes("api_key"))).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe("type field validation", () => {
|
|
224
|
+
it('should require type to be "mindsim_service_account"', () => {
|
|
225
|
+
const result = validateServiceJson(createValidServiceJson({ type: "other_type" }));
|
|
226
|
+
expect(result.valid).toBe(false);
|
|
227
|
+
expect(result.errors.some((e) => e.includes("mindsim_service_account"))).toBe(true);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe("environment field validation", () => {
|
|
232
|
+
it('should require environment to be "production"', () => {
|
|
233
|
+
const result = validateServiceJson(createValidServiceJson({ environment: "development" }));
|
|
234
|
+
expect(result.valid).toBe(false);
|
|
235
|
+
expect(result.errors.some((e) => e.includes("production"))).toBe(true);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe("email validation (Gap 8)", () => {
|
|
240
|
+
it("should accept valid email addresses", () => {
|
|
241
|
+
const result = validateServiceJson(
|
|
242
|
+
createValidServiceJson({ client_email: "service@my-app.mindsim.io" }),
|
|
243
|
+
);
|
|
244
|
+
expect(result.valid).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should reject email without @", () => {
|
|
248
|
+
const result = validateServiceJson(
|
|
249
|
+
createValidServiceJson({ client_email: "invalid-email" }),
|
|
250
|
+
);
|
|
251
|
+
expect(result.valid).toBe(false);
|
|
252
|
+
expect(result.errors.some((e) => e.includes("valid email"))).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should reject email without domain", () => {
|
|
256
|
+
const result = validateServiceJson(createValidServiceJson({ client_email: "user@" }));
|
|
257
|
+
expect(result.valid).toBe(false);
|
|
258
|
+
expect(result.errors.some((e) => e.includes("valid email"))).toBe(true);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should reject email with spaces", () => {
|
|
262
|
+
const result = validateServiceJson(
|
|
263
|
+
createValidServiceJson({ client_email: "user @domain.com" }),
|
|
264
|
+
);
|
|
265
|
+
expect(result.valid).toBe(false);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("UUID validation", () => {
|
|
270
|
+
it("should validate client_id as UUID", () => {
|
|
271
|
+
const result = validateServiceJson(
|
|
272
|
+
createValidServiceJson({ client_id: "not-a-valid-uuid" }),
|
|
273
|
+
);
|
|
274
|
+
expect(result.valid).toBe(false);
|
|
275
|
+
expect(result.errors.some((e) => e.includes("client_id") && e.includes("UUID"))).toBe(true);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("should validate app_metadata.app_id as UUID", () => {
|
|
279
|
+
const result = validateServiceJson(
|
|
280
|
+
createValidServiceJson({
|
|
281
|
+
app_metadata: {
|
|
282
|
+
app_id: "invalid",
|
|
283
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
284
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
285
|
+
use_case: "internal-workflow",
|
|
286
|
+
},
|
|
287
|
+
}),
|
|
288
|
+
);
|
|
289
|
+
expect(result.valid).toBe(false);
|
|
290
|
+
expect(result.errors.some((e) => e.includes("app_id") && e.includes("UUID"))).toBe(true);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("should validate app_metadata.workspace_id as UUID", () => {
|
|
294
|
+
const result = validateServiceJson(
|
|
295
|
+
createValidServiceJson({
|
|
296
|
+
app_metadata: {
|
|
297
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
298
|
+
workspace_id: "not-uuid",
|
|
299
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
300
|
+
use_case: "internal-workflow",
|
|
301
|
+
},
|
|
302
|
+
}),
|
|
303
|
+
);
|
|
304
|
+
expect(result.valid).toBe(false);
|
|
305
|
+
expect(result.errors.some((e) => e.includes("workspace_id") && e.includes("UUID"))).toBe(
|
|
306
|
+
true,
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("should validate app_metadata.mindsim_org_id as UUID", () => {
|
|
311
|
+
const result = validateServiceJson(
|
|
312
|
+
createValidServiceJson({
|
|
313
|
+
app_metadata: {
|
|
314
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
315
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
316
|
+
mindsim_org_id: "bad-uuid",
|
|
317
|
+
use_case: "internal-workflow",
|
|
318
|
+
},
|
|
319
|
+
}),
|
|
320
|
+
);
|
|
321
|
+
expect(result.valid).toBe(false);
|
|
322
|
+
expect(result.errors.some((e) => e.includes("mindsim_org_id") && e.includes("UUID"))).toBe(
|
|
323
|
+
true,
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
describe("URL validation", () => {
|
|
329
|
+
it("should validate api_base_url as HTTPS URL", () => {
|
|
330
|
+
const result = validateServiceJson(
|
|
331
|
+
createValidServiceJson({ api_base_url: "http://insecure.com" }),
|
|
332
|
+
);
|
|
333
|
+
expect(result.valid).toBe(false);
|
|
334
|
+
expect(result.errors.some((e) => e.includes("api_base_url") && e.includes("HTTPS"))).toBe(
|
|
335
|
+
true,
|
|
336
|
+
);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("should accept valid HTTPS URL", () => {
|
|
340
|
+
const result = validateServiceJson(
|
|
341
|
+
createValidServiceJson({ api_base_url: "https://api.example.com/v1" }),
|
|
342
|
+
);
|
|
343
|
+
expect(result.valid).toBe(true);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it("should reject invalid URL format", () => {
|
|
347
|
+
const result = validateServiceJson(createValidServiceJson({ api_base_url: "not-a-url" }));
|
|
348
|
+
expect(result.valid).toBe(false);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe("timestamp validation", () => {
|
|
353
|
+
it("should validate created_at as ISO 8601", () => {
|
|
354
|
+
const result = validateServiceJson(
|
|
355
|
+
createValidServiceJson({ created_at: "not-a-timestamp" }),
|
|
356
|
+
);
|
|
357
|
+
expect(result.valid).toBe(false);
|
|
358
|
+
expect(result.errors.some((e) => e.includes("created_at") && e.includes("ISO 8601"))).toBe(
|
|
359
|
+
true,
|
|
360
|
+
);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("should accept valid ISO 8601 timestamp", () => {
|
|
364
|
+
const result = validateServiceJson(
|
|
365
|
+
createValidServiceJson({ created_at: "2025-12-21T12:30:45.123Z" }),
|
|
366
|
+
);
|
|
367
|
+
expect(result.valid).toBe(true);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("should validate expires_at if present", () => {
|
|
371
|
+
const result = validateServiceJson(createValidServiceJson({ expires_at: "bad-date" }));
|
|
372
|
+
expect(result.valid).toBe(false);
|
|
373
|
+
expect(result.errors.some((e) => e.includes("expires_at"))).toBe(true);
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe("scopes validation", () => {
|
|
378
|
+
it("should require scopes to be an array", () => {
|
|
379
|
+
const result = validateServiceJson(createValidServiceJson({ scopes: "not-array" }));
|
|
380
|
+
expect(result.valid).toBe(false);
|
|
381
|
+
expect(result.errors.some((e) => e.includes("scopes") && e.includes("array"))).toBe(true);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("should reject empty scopes array", () => {
|
|
385
|
+
const result = validateServiceJson(createValidServiceJson({ scopes: [] }));
|
|
386
|
+
expect(result.valid).toBe(false);
|
|
387
|
+
expect(result.errors.some((e) => e.includes("scopes") && e.includes("empty"))).toBe(true);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("should reject invalid scope values", () => {
|
|
391
|
+
const result = validateServiceJson(
|
|
392
|
+
createValidServiceJson({ scopes: ["minds:read", "invalid:scope"] }),
|
|
393
|
+
);
|
|
394
|
+
expect(result.valid).toBe(false);
|
|
395
|
+
expect(result.errors.some((e) => e.includes("invalid:scope"))).toBe(true);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it("should accept all valid scopes", () => {
|
|
399
|
+
const validScopes = [
|
|
400
|
+
"minds:read",
|
|
401
|
+
"minds:write",
|
|
402
|
+
"simulate:run",
|
|
403
|
+
"simulate:read",
|
|
404
|
+
"users:read",
|
|
405
|
+
"users:write",
|
|
406
|
+
"org:admin",
|
|
407
|
+
];
|
|
408
|
+
const result = validateServiceJson(createValidServiceJson({ scopes: validScopes }));
|
|
409
|
+
expect(result.valid).toBe(true);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
describe("app_metadata validation", () => {
|
|
414
|
+
it("should require app_metadata object", () => {
|
|
415
|
+
const result = validateServiceJson(createValidServiceJson({ app_metadata: undefined }));
|
|
416
|
+
expect(result.valid).toBe(false);
|
|
417
|
+
expect(result.errors.some((e) => e.includes("app_metadata"))).toBe(true);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it("should require use_case in app_metadata", () => {
|
|
421
|
+
const result = validateServiceJson(
|
|
422
|
+
createValidServiceJson({
|
|
423
|
+
app_metadata: {
|
|
424
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
425
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
426
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
427
|
+
use_case: "invalid-use-case",
|
|
428
|
+
},
|
|
429
|
+
}),
|
|
430
|
+
);
|
|
431
|
+
expect(result.valid).toBe(false);
|
|
432
|
+
expect(result.errors.some((e) => e.includes("use_case"))).toBe(true);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("should accept valid use_case values", () => {
|
|
436
|
+
for (const useCase of ["internal-workflow", "customer-facing", "agentic-ai"]) {
|
|
437
|
+
const result = validateServiceJson(
|
|
438
|
+
createValidServiceJson({
|
|
439
|
+
app_metadata: {
|
|
440
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
441
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
442
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
443
|
+
use_case: useCase,
|
|
444
|
+
},
|
|
445
|
+
}),
|
|
446
|
+
);
|
|
447
|
+
expect(result.valid).toBe(true);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
describe("loadServiceJsonFromBase64", () => {
|
|
454
|
+
const validServiceJson = {
|
|
455
|
+
type: "mindsim_service_account",
|
|
456
|
+
version: "1",
|
|
457
|
+
project_id: "test-app",
|
|
458
|
+
project_name: "Test App",
|
|
459
|
+
environment: "production",
|
|
460
|
+
client_email: "service@test-app.mindsim.io",
|
|
461
|
+
client_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
462
|
+
api_key: "ms_prod_abc123",
|
|
463
|
+
api_base_url: "https://api.reasoner.com/api/mindsim",
|
|
464
|
+
scopes: ["minds:read"],
|
|
465
|
+
app_metadata: {
|
|
466
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
467
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
468
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
469
|
+
use_case: "internal-workflow",
|
|
470
|
+
},
|
|
471
|
+
created_at: "2025-12-21T00:00:00.000Z",
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
it("should decode valid base64 service JSON", () => {
|
|
475
|
+
const base64 = Buffer.from(JSON.stringify(validServiceJson)).toString("base64");
|
|
476
|
+
const result = loadServiceJsonFromBase64(base64);
|
|
477
|
+
expect(result).not.toBeNull();
|
|
478
|
+
expect(result?.project_id).toBe("test-app");
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it("should return null for empty base64 string", () => {
|
|
482
|
+
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
483
|
+
const result = loadServiceJsonFromBase64("");
|
|
484
|
+
expect(result).toBeNull();
|
|
485
|
+
consoleSpy.mockRestore();
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it("should return null for invalid base64", () => {
|
|
489
|
+
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
490
|
+
const result = loadServiceJsonFromBase64("not-valid-base64!!!");
|
|
491
|
+
expect(result).toBeNull();
|
|
492
|
+
consoleSpy.mockRestore();
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it("should return null for base64 with invalid JSON", () => {
|
|
496
|
+
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
497
|
+
const base64 = Buffer.from("not valid json").toString("base64");
|
|
498
|
+
const result = loadServiceJsonFromBase64(base64);
|
|
499
|
+
expect(result).toBeNull();
|
|
500
|
+
consoleSpy.mockRestore();
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
describe("loadServiceJson", () => {
|
|
505
|
+
it("should load from MINDSIM_SERVICE_JSON file path", () => {
|
|
506
|
+
const validServiceJson = {
|
|
507
|
+
type: "mindsim_service_account",
|
|
508
|
+
version: "1",
|
|
509
|
+
project_id: "test-app",
|
|
510
|
+
project_name: "Test App",
|
|
511
|
+
environment: "production",
|
|
512
|
+
client_email: "service@test-app.mindsim.io",
|
|
513
|
+
client_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
514
|
+
api_key: "ms_prod_abc123",
|
|
515
|
+
api_base_url: "https://api.reasoner.com/api/mindsim",
|
|
516
|
+
scopes: ["minds:read"],
|
|
517
|
+
app_metadata: {
|
|
518
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
519
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
520
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
521
|
+
use_case: "internal-workflow",
|
|
522
|
+
},
|
|
523
|
+
created_at: "2025-12-21T00:00:00.000Z",
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
vi.stubEnv("MINDSIM_SERVICE_JSON", "/path/to/service.json");
|
|
527
|
+
mockedFs.existsSync.mockReturnValue(true);
|
|
528
|
+
mockedFs.readFileSync.mockReturnValue(JSON.stringify(validServiceJson));
|
|
529
|
+
|
|
530
|
+
const result = loadServiceJson();
|
|
531
|
+
expect(result).not.toBeNull();
|
|
532
|
+
expect(result?.project_id).toBe("test-app");
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it("should load from MINDSIM_SERVICE_JSON_BASE64", () => {
|
|
536
|
+
const validServiceJson = {
|
|
537
|
+
type: "mindsim_service_account",
|
|
538
|
+
version: "1",
|
|
539
|
+
project_id: "base64-app",
|
|
540
|
+
project_name: "Base64 App",
|
|
541
|
+
environment: "production",
|
|
542
|
+
client_email: "service@base64-app.mindsim.io",
|
|
543
|
+
client_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
544
|
+
api_key: "ms_prod_abc123",
|
|
545
|
+
api_base_url: "https://api.reasoner.com/api/mindsim",
|
|
546
|
+
scopes: ["minds:read"],
|
|
547
|
+
app_metadata: {
|
|
548
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
549
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
550
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
551
|
+
use_case: "internal-workflow",
|
|
552
|
+
},
|
|
553
|
+
created_at: "2025-12-21T00:00:00.000Z",
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const base64 = Buffer.from(JSON.stringify(validServiceJson)).toString("base64");
|
|
557
|
+
vi.stubEnv("MINDSIM_SERVICE_JSON_BASE64", base64);
|
|
558
|
+
mockedFs.existsSync.mockReturnValue(false); // No file
|
|
559
|
+
|
|
560
|
+
const result = loadServiceJson();
|
|
561
|
+
expect(result).not.toBeNull();
|
|
562
|
+
expect(result?.project_id).toBe("base64-app");
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it("should prioritize file path over base64", () => {
|
|
566
|
+
const fileServiceJson = {
|
|
567
|
+
type: "mindsim_service_account",
|
|
568
|
+
version: "1",
|
|
569
|
+
project_id: "file-app",
|
|
570
|
+
project_name: "File App",
|
|
571
|
+
environment: "production",
|
|
572
|
+
client_email: "service@file-app.mindsim.io",
|
|
573
|
+
client_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
574
|
+
api_key: "ms_prod_abc123",
|
|
575
|
+
api_base_url: "https://api.reasoner.com/api/mindsim",
|
|
576
|
+
scopes: ["minds:read"],
|
|
577
|
+
app_metadata: {
|
|
578
|
+
app_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
579
|
+
workspace_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
580
|
+
mindsim_org_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
581
|
+
use_case: "internal-workflow",
|
|
582
|
+
},
|
|
583
|
+
created_at: "2025-12-21T00:00:00.000Z",
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
const base64ServiceJson = { ...fileServiceJson, project_id: "base64-app" };
|
|
587
|
+
const base64 = Buffer.from(JSON.stringify(base64ServiceJson)).toString("base64");
|
|
588
|
+
|
|
589
|
+
vi.stubEnv("MINDSIM_SERVICE_JSON", "/path/to/service.json");
|
|
590
|
+
vi.stubEnv("MINDSIM_SERVICE_JSON_BASE64", base64);
|
|
591
|
+
mockedFs.existsSync.mockReturnValue(true);
|
|
592
|
+
mockedFs.readFileSync.mockReturnValue(JSON.stringify(fileServiceJson));
|
|
593
|
+
|
|
594
|
+
const result = loadServiceJson();
|
|
595
|
+
expect(result?.project_id).toBe("file-app"); // File takes priority
|
|
596
|
+
});
|
|
133
597
|
});
|
|
134
598
|
});
|