timeback 0.2.2-beta.20260401002024 → 0.2.2-beta.20260402000431
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +310 -121
- package/package.json +1 -1
- package/schema.json +79 -112
package/dist/cli.js
CHANGED
|
@@ -26823,7 +26823,7 @@ function date4(params) {
|
|
|
26823
26823
|
|
|
26824
26824
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
26825
26825
|
config(en_default());
|
|
26826
|
-
// ../clients/core/dist/chunk-
|
|
26826
|
+
// ../clients/core/dist/chunk-bq65zn6q.js
|
|
26827
26827
|
var log3 = createScopedLogger("edubridge");
|
|
26828
26828
|
function normalizeBoolean(value) {
|
|
26829
26829
|
if (typeof value === "boolean")
|
|
@@ -26995,6 +26995,13 @@ var StringTimebackGrade = exports_external.string().transform((value, ctx) => {
|
|
|
26995
26995
|
return exports_external.NEVER;
|
|
26996
26996
|
}
|
|
26997
26997
|
const stripped = raw.replace(/\bgrade\b/g, "").replace(/(\d+)(st|nd|rd|th)\b/g, "$1").trim();
|
|
26998
|
+
if (stripped === "") {
|
|
26999
|
+
ctx.addIssue({
|
|
27000
|
+
code: "custom",
|
|
27001
|
+
message: "must be a valid Timeback grade"
|
|
27002
|
+
});
|
|
27003
|
+
return exports_external.NEVER;
|
|
27004
|
+
}
|
|
26998
27005
|
if (stripped === "pre-k" || stripped === "pk") {
|
|
26999
27006
|
return -1;
|
|
27000
27007
|
}
|
|
@@ -33251,6 +33258,13 @@ var StringTimebackGrade2 = exports_external.string().transform((value, ctx) => {
|
|
|
33251
33258
|
return exports_external.NEVER;
|
|
33252
33259
|
}
|
|
33253
33260
|
const stripped = raw.replace(/\bgrade\b/g, "").replace(/(\d+)(st|nd|rd|th)\b/g, "$1").trim();
|
|
33261
|
+
if (stripped === "") {
|
|
33262
|
+
ctx.addIssue({
|
|
33263
|
+
code: "custom",
|
|
33264
|
+
message: "must be a valid Timeback grade"
|
|
33265
|
+
});
|
|
33266
|
+
return exports_external.NEVER;
|
|
33267
|
+
}
|
|
33254
33268
|
if (stripped === "pre-k" || stripped === "pk") {
|
|
33255
33269
|
return -1;
|
|
33256
33270
|
}
|
|
@@ -35111,8 +35125,13 @@ var CredentialsSchema = exports_external.object({
|
|
|
35111
35125
|
clientSecret: NonEmptyString2,
|
|
35112
35126
|
email: exports_external.email("Valid email is required").optional()
|
|
35113
35127
|
});
|
|
35114
|
-
var
|
|
35115
|
-
|
|
35128
|
+
var StoredCredentialsSchema = exports_external.object({
|
|
35129
|
+
clientId: NonEmptyString2.optional(),
|
|
35130
|
+
clientSecret: NonEmptyString2.optional(),
|
|
35131
|
+
email: exports_external.email("Valid email is required").optional()
|
|
35132
|
+
}).refine((value) => value.email || value.clientId && value.clientSecret, "Saved credentials must include an email or a client ID/client secret pair").refine((value) => Boolean(value.clientId) === Boolean(value.clientSecret), "Saved credentials must include both client ID and client secret");
|
|
35133
|
+
var ClientIdSchema = exports_external.string().min(1, "Client ID is required").max(128, "Client ID must be at most 128 characters").regex(/^[\w+]+$/, "Client ID must contain only letters, digits, underscores, or +");
|
|
35134
|
+
var ClientSecretSchema = exports_external.string().min(24, "Client secret must be at least 24 characters").max(64, "Client secret must be at most 64 characters").regex(/^[\w+]+$/, "Client secret must contain only letters, digits, underscores, or +");
|
|
35116
35135
|
var MasteryTrackCredentialsSchema = exports_external.object({
|
|
35117
35136
|
apiKey: NonEmptyString2,
|
|
35118
35137
|
email: exports_external.email("Valid email is required")
|
|
@@ -36344,24 +36363,41 @@ async function writeCredentialsStore(store) {
|
|
|
36344
36363
|
await writeFile(CREDENTIALS_FILE, JSON.stringify(cleaned, null, 2), { mode: 384 });
|
|
36345
36364
|
return true;
|
|
36346
36365
|
}
|
|
36347
|
-
|
|
36348
|
-
const store = await readCredentialsStore();
|
|
36366
|
+
function getStoredCredentialsFromStore(store, environment) {
|
|
36349
36367
|
const namespaced = store.timeback?.[environment];
|
|
36350
36368
|
if (namespaced) {
|
|
36351
|
-
const result =
|
|
36369
|
+
const result = StoredCredentialsSchema.safeParse(namespaced);
|
|
36352
36370
|
if (result.success) {
|
|
36353
36371
|
return result.data;
|
|
36354
36372
|
}
|
|
36355
36373
|
}
|
|
36356
36374
|
const legacy = store[environment];
|
|
36357
36375
|
if (legacy) {
|
|
36358
|
-
const result =
|
|
36376
|
+
const result = StoredCredentialsSchema.safeParse(legacy);
|
|
36359
36377
|
if (result.success) {
|
|
36360
36378
|
return result.data;
|
|
36361
36379
|
}
|
|
36362
36380
|
}
|
|
36363
36381
|
return null;
|
|
36364
36382
|
}
|
|
36383
|
+
async function getStoredCredentials(environment) {
|
|
36384
|
+
const store = await readCredentialsStore();
|
|
36385
|
+
return getStoredCredentialsFromStore(store, environment);
|
|
36386
|
+
}
|
|
36387
|
+
function toCredentials(stored) {
|
|
36388
|
+
if (stored?.clientId && stored.clientSecret) {
|
|
36389
|
+
return {
|
|
36390
|
+
clientId: stored.clientId,
|
|
36391
|
+
clientSecret: stored.clientSecret,
|
|
36392
|
+
email: stored.email
|
|
36393
|
+
};
|
|
36394
|
+
}
|
|
36395
|
+
return null;
|
|
36396
|
+
}
|
|
36397
|
+
async function getSavedCredentials(environment) {
|
|
36398
|
+
const stored = await getStoredCredentials(environment);
|
|
36399
|
+
return toCredentials(stored);
|
|
36400
|
+
}
|
|
36365
36401
|
async function saveCredentials(environment, credentials) {
|
|
36366
36402
|
const store = await readCredentialsStore();
|
|
36367
36403
|
store.timeback = store.timeback ?? {};
|
|
@@ -36369,6 +36405,44 @@ async function saveCredentials(environment, credentials) {
|
|
|
36369
36405
|
delete store[environment];
|
|
36370
36406
|
return writeCredentialsStore(store);
|
|
36371
36407
|
}
|
|
36408
|
+
async function saveCredentialEmail(environment, email3) {
|
|
36409
|
+
const store = await readCredentialsStore();
|
|
36410
|
+
const existing = getStoredCredentialsFromStore(store, environment);
|
|
36411
|
+
if (email3) {
|
|
36412
|
+
store.timeback = store.timeback ?? {};
|
|
36413
|
+
store.timeback[environment] = {
|
|
36414
|
+
...existing ?? {},
|
|
36415
|
+
email: email3
|
|
36416
|
+
};
|
|
36417
|
+
} else if (existing?.clientId && existing.clientSecret) {
|
|
36418
|
+
store.timeback = store.timeback ?? {};
|
|
36419
|
+
store.timeback[environment] = {
|
|
36420
|
+
clientId: existing.clientId,
|
|
36421
|
+
clientSecret: existing.clientSecret
|
|
36422
|
+
};
|
|
36423
|
+
} else {
|
|
36424
|
+
delete store.timeback?.[environment];
|
|
36425
|
+
if (store.timeback && Object.keys(store.timeback).length === 0) {
|
|
36426
|
+
delete store.timeback;
|
|
36427
|
+
}
|
|
36428
|
+
}
|
|
36429
|
+
delete store[environment];
|
|
36430
|
+
return writeCredentialsStore(store);
|
|
36431
|
+
}
|
|
36432
|
+
async function getStoredCredentialEmail(environment) {
|
|
36433
|
+
const stored = await getStoredCredentials(environment);
|
|
36434
|
+
return stored?.email;
|
|
36435
|
+
}
|
|
36436
|
+
async function getEnvironmentsWithStoredEmail() {
|
|
36437
|
+
const store = await readCredentialsStore();
|
|
36438
|
+
const environments = [];
|
|
36439
|
+
for (const env2 of ENVIRONMENTS) {
|
|
36440
|
+
if (getStoredCredentialsFromStore(store, env2)?.email) {
|
|
36441
|
+
environments.push(env2);
|
|
36442
|
+
}
|
|
36443
|
+
}
|
|
36444
|
+
return environments;
|
|
36445
|
+
}
|
|
36372
36446
|
async function clearCredentials(environment) {
|
|
36373
36447
|
const store = await readCredentialsStore();
|
|
36374
36448
|
if (environment) {
|
|
@@ -36389,18 +36463,23 @@ async function getConfiguredEnvironments() {
|
|
|
36389
36463
|
const store = await readCredentialsStore();
|
|
36390
36464
|
const configured = [];
|
|
36391
36465
|
for (const env2 of ENVIRONMENTS) {
|
|
36392
|
-
|
|
36393
|
-
if (namespaced && CredentialsSchema.safeParse(namespaced).success) {
|
|
36394
|
-
configured.push(env2);
|
|
36395
|
-
continue;
|
|
36396
|
-
}
|
|
36397
|
-
const legacy = store[env2];
|
|
36398
|
-
if (legacy && CredentialsSchema.safeParse(legacy).success) {
|
|
36466
|
+
if (toCredentials(getStoredCredentialsFromStore(store, env2))) {
|
|
36399
36467
|
configured.push(env2);
|
|
36400
36468
|
}
|
|
36401
36469
|
}
|
|
36402
36470
|
return configured;
|
|
36403
36471
|
}
|
|
36472
|
+
async function getAvailableEnvironments() {
|
|
36473
|
+
const available = await getConfiguredEnvironments();
|
|
36474
|
+
if (getEnvCredentials()) {
|
|
36475
|
+
for (const env2 of ENVIRONMENTS) {
|
|
36476
|
+
if (!available.includes(env2)) {
|
|
36477
|
+
available.push(env2);
|
|
36478
|
+
}
|
|
36479
|
+
}
|
|
36480
|
+
}
|
|
36481
|
+
return available;
|
|
36482
|
+
}
|
|
36404
36483
|
function getEnvCredentials() {
|
|
36405
36484
|
const clientId = process.env.TIMEBACK_API_CLIENT_ID ?? process.env.TIMEBACK_CLIENT_ID;
|
|
36406
36485
|
const clientSecret = process.env.TIMEBACK_API_CLIENT_SECRET ?? process.env.TIMEBACK_CLIENT_SECRET;
|
|
@@ -36414,10 +36493,12 @@ function getEnvCredentials() {
|
|
|
36414
36493
|
}
|
|
36415
36494
|
async function loadCredentials(environment) {
|
|
36416
36495
|
const envCreds = getEnvCredentials();
|
|
36496
|
+
const storedCreds = await getStoredCredentials(environment);
|
|
36417
36497
|
if (envCreds) {
|
|
36418
|
-
|
|
36498
|
+
const merged = storedCreds?.email ? { ...envCreds, email: storedCreds.email } : envCreds;
|
|
36499
|
+
return { success: true, credentials: merged, source: "env" };
|
|
36419
36500
|
}
|
|
36420
|
-
const savedCreds =
|
|
36501
|
+
const savedCreds = toCredentials(storedCreds);
|
|
36421
36502
|
if (savedCreds) {
|
|
36422
36503
|
return { success: true, credentials: savedCreds, source: "saved" };
|
|
36423
36504
|
}
|
|
@@ -39302,7 +39383,7 @@ You need to configure your Timeback API credentials first.`, "Credentials Setup"
|
|
|
39302
39383
|
}
|
|
39303
39384
|
async function runImportFlow(opts = {}) {
|
|
39304
39385
|
const { format: format2 = true } = opts;
|
|
39305
|
-
let configuredEnvs = await
|
|
39386
|
+
let configuredEnvs = await getAvailableEnvironments();
|
|
39306
39387
|
if (configuredEnvs.length === 0) {
|
|
39307
39388
|
const setupResult = await setupCredentials();
|
|
39308
39389
|
if (setupResult === "cancelled") {
|
|
@@ -39311,7 +39392,7 @@ async function runImportFlow(opts = {}) {
|
|
|
39311
39392
|
if (setupResult === "error") {
|
|
39312
39393
|
return { success: false, error: "Credential validation failed" };
|
|
39313
39394
|
}
|
|
39314
|
-
configuredEnvs = await
|
|
39395
|
+
configuredEnvs = await getAvailableEnvironments();
|
|
39315
39396
|
if (configuredEnvs.length === 0) {
|
|
39316
39397
|
return { success: false, error: "Failed to configure credentials" };
|
|
39317
39398
|
}
|
|
@@ -40652,6 +40733,13 @@ var StringTimebackGrade3 = exports_external.string().transform((value, ctx) => {
|
|
|
40652
40733
|
return exports_external.NEVER;
|
|
40653
40734
|
}
|
|
40654
40735
|
const stripped = raw.replace(/\bgrade\b/g, "").replace(/(\d+)(st|nd|rd|th)\b/g, "$1").trim();
|
|
40736
|
+
if (stripped === "") {
|
|
40737
|
+
ctx.addIssue({
|
|
40738
|
+
code: "custom",
|
|
40739
|
+
message: "must be a valid Timeback grade"
|
|
40740
|
+
});
|
|
40741
|
+
return exports_external.NEVER;
|
|
40742
|
+
}
|
|
40655
40743
|
if (stripped === "pre-k" || stripped === "pk") {
|
|
40656
40744
|
return -1;
|
|
40657
40745
|
}
|
|
@@ -47224,11 +47312,15 @@ function exitCancelled(isOverwriting, exitOnComplete) {
|
|
|
47224
47312
|
// src/commands/credentials/email.ts
|
|
47225
47313
|
async function updateEmail(options = {}) {
|
|
47226
47314
|
const { exitOnComplete = true, env: envOption } = options;
|
|
47227
|
-
const
|
|
47228
|
-
|
|
47229
|
-
|
|
47230
|
-
|
|
47231
|
-
|
|
47315
|
+
const emailEnvs = await getEnvironmentsWithStoredEmail();
|
|
47316
|
+
const requestedEnv = envOption && ENVIRONMENTS.includes(envOption) ? envOption : undefined;
|
|
47317
|
+
let configuredEnvs;
|
|
47318
|
+
if (requestedEnv) {
|
|
47319
|
+
const hasStoredEmail = await getStoredCredentialEmail(requestedEnv);
|
|
47320
|
+
const hasUsableCredentials = (await loadCredentials(requestedEnv)).success;
|
|
47321
|
+
configuredEnvs = hasStoredEmail || hasUsableCredentials ? [requestedEnv] : [];
|
|
47322
|
+
} else {
|
|
47323
|
+
configuredEnvs = [...new Set([...await getAvailableEnvironments(), ...emailEnvs])];
|
|
47232
47324
|
}
|
|
47233
47325
|
if (configuredEnvs.length === 0) {
|
|
47234
47326
|
M2.warn("No credentials configured");
|
|
@@ -47258,15 +47350,8 @@ async function updateEmail(options = {}) {
|
|
|
47258
47350
|
}
|
|
47259
47351
|
targetEnv = selected;
|
|
47260
47352
|
}
|
|
47261
|
-
const
|
|
47262
|
-
|
|
47263
|
-
M2.error("Credentials not found");
|
|
47264
|
-
outro.error("Credentials not found");
|
|
47265
|
-
if (exitOnComplete)
|
|
47266
|
-
process.exit(0);
|
|
47267
|
-
return false;
|
|
47268
|
-
}
|
|
47269
|
-
const currentEmail = currentCreds.email;
|
|
47353
|
+
const currentCredsResult = await loadCredentials(targetEnv);
|
|
47354
|
+
const currentEmail = currentCredsResult.success ? currentCredsResult.credentials.email : await getStoredCredentialEmail(targetEnv);
|
|
47270
47355
|
const message = currentEmail ? `Email ${dim(`(current: ${currentEmail})`)}` : `Email ${dim("(not set)")}`;
|
|
47271
47356
|
const email3 = await he({
|
|
47272
47357
|
message,
|
|
@@ -47295,6 +47380,14 @@ async function updateEmail(options = {}) {
|
|
|
47295
47380
|
return true;
|
|
47296
47381
|
}
|
|
47297
47382
|
if (normalizedEmail) {
|
|
47383
|
+
if (!currentCredsResult.success) {
|
|
47384
|
+
M2.error("Credentials required to set email");
|
|
47385
|
+
outro.error("Credentials required to set email");
|
|
47386
|
+
if (exitOnComplete)
|
|
47387
|
+
process.exit(0);
|
|
47388
|
+
return false;
|
|
47389
|
+
}
|
|
47390
|
+
const currentCreds = currentCredsResult.credentials;
|
|
47298
47391
|
const s = Y2();
|
|
47299
47392
|
s.start("Validating email...");
|
|
47300
47393
|
const result = await validateEmailWithTimeback(targetEnv, currentCreds.clientId, currentCreds.clientSecret, normalizedEmail);
|
|
@@ -47315,10 +47408,7 @@ async function updateEmail(options = {}) {
|
|
|
47315
47408
|
email: normalizedEmail
|
|
47316
47409
|
});
|
|
47317
47410
|
if (accountCreated) {
|
|
47318
|
-
await
|
|
47319
|
-
...currentCreds,
|
|
47320
|
-
email: normalizedEmail
|
|
47321
|
-
});
|
|
47411
|
+
await saveCredentialEmail(targetEnv, normalizedEmail);
|
|
47322
47412
|
M2.success(`Email saved for ${targetEnv}`);
|
|
47323
47413
|
outro.success();
|
|
47324
47414
|
} else {
|
|
@@ -47328,20 +47418,14 @@ async function updateEmail(options = {}) {
|
|
|
47328
47418
|
process.exit(0);
|
|
47329
47419
|
return accountCreated;
|
|
47330
47420
|
}
|
|
47331
|
-
await
|
|
47332
|
-
...currentCreds,
|
|
47333
|
-
email: normalizedEmail
|
|
47334
|
-
});
|
|
47421
|
+
await saveCredentialEmail(targetEnv, normalizedEmail);
|
|
47335
47422
|
s.stop(green(`Email updated for ${targetEnv}`));
|
|
47336
47423
|
outro.success();
|
|
47337
47424
|
if (exitOnComplete)
|
|
47338
47425
|
process.exit(0);
|
|
47339
47426
|
return true;
|
|
47340
47427
|
}
|
|
47341
|
-
await
|
|
47342
|
-
...currentCreds,
|
|
47343
|
-
email: undefined
|
|
47344
|
-
});
|
|
47428
|
+
await saveCredentialEmail(targetEnv, undefined);
|
|
47345
47429
|
outro.success(`Email cleared for ${targetEnv}`);
|
|
47346
47430
|
if (exitOnComplete)
|
|
47347
47431
|
process.exit(0);
|
|
@@ -47359,13 +47443,19 @@ async function listCredentials(options = {}) {
|
|
|
47359
47443
|
const { exitOnComplete = true } = options;
|
|
47360
47444
|
const timebackLines = [];
|
|
47361
47445
|
const masteryTrackLines = [];
|
|
47446
|
+
const envCreds = getEnvCredentials();
|
|
47362
47447
|
let hasAnyTimeback = false;
|
|
47363
47448
|
let hasAnyMasteryTrack = false;
|
|
47449
|
+
let hasSavedTimeback = false;
|
|
47450
|
+
const hasEnvTimeback = Boolean(envCreds);
|
|
47364
47451
|
for (const env2 of ENVIRONMENTS) {
|
|
47365
47452
|
const creds = await getSavedCredentials(env2);
|
|
47366
|
-
if (creds) {
|
|
47453
|
+
if (creds && hasEnvTimeback) {
|
|
47454
|
+
timebackLines.push(`${dim("●")} ${env2}: ${creds.clientId}`);
|
|
47455
|
+
hasSavedTimeback = true;
|
|
47456
|
+
} else if (creds) {
|
|
47367
47457
|
timebackLines.push(`${green("●")} ${env2}: ${creds.clientId}`);
|
|
47368
|
-
|
|
47458
|
+
hasSavedTimeback = true;
|
|
47369
47459
|
} else {
|
|
47370
47460
|
timebackLines.push(`${dim("○")} ${env2}: not configured`);
|
|
47371
47461
|
}
|
|
@@ -47377,12 +47467,26 @@ async function listCredentials(options = {}) {
|
|
|
47377
47467
|
masteryTrackLines.push(`${dim("○")} ${env2}: not configured`);
|
|
47378
47468
|
}
|
|
47379
47469
|
}
|
|
47470
|
+
hasAnyTimeback = hasSavedTimeback || hasEnvTimeback;
|
|
47471
|
+
if (envCreds) {
|
|
47472
|
+
timebackLines.push(`${green("●")} env: ${envCreds.clientId} ${yellow("[override]")}`);
|
|
47473
|
+
}
|
|
47380
47474
|
Me(timebackLines.join(`
|
|
47381
47475
|
`), "Timeback");
|
|
47382
47476
|
Me(masteryTrackLines.join(`
|
|
47383
47477
|
`), "MasteryTrack");
|
|
47384
47478
|
if (hasAnyTimeback || hasAnyMasteryTrack) {
|
|
47385
|
-
|
|
47479
|
+
const details = [];
|
|
47480
|
+
if (hasSavedTimeback || hasAnyMasteryTrack) {
|
|
47481
|
+
details.push(`Credentials stored in ${blueBright(underline(tildify(getCredentialsPath())))}`);
|
|
47482
|
+
}
|
|
47483
|
+
if (hasEnvTimeback) {
|
|
47484
|
+
details.push("Timeback env credentials are active");
|
|
47485
|
+
}
|
|
47486
|
+
if (details.length > 0) {
|
|
47487
|
+
outro.info(details.join(`
|
|
47488
|
+
`));
|
|
47489
|
+
}
|
|
47386
47490
|
} else {
|
|
47387
47491
|
const shouldAdd = await ye({
|
|
47388
47492
|
message: "No credentials configured. Add now?"
|
|
@@ -47424,7 +47528,7 @@ async function removeCredentials(options = {}) {
|
|
|
47424
47528
|
configuredEnvs.push(env2);
|
|
47425
47529
|
}
|
|
47426
47530
|
if (configuredEnvs.length === 0) {
|
|
47427
|
-
M2.warn(provider === "masterytrack" ? "No MasteryTrack credentials configured" : "No credentials configured");
|
|
47531
|
+
M2.warn(provider === "masterytrack" ? "No saved MasteryTrack credentials configured" : "No saved credentials configured");
|
|
47428
47532
|
if (exitOnComplete)
|
|
47429
47533
|
process.exit(0);
|
|
47430
47534
|
return;
|
|
@@ -48243,7 +48347,7 @@ You need to configure your Timeback API credentials first.`, "Credentials Setup"
|
|
|
48243
48347
|
return "ok";
|
|
48244
48348
|
}
|
|
48245
48349
|
async function ensureConfiguredEnvironments(targetEnv) {
|
|
48246
|
-
let configuredEnvs = await
|
|
48350
|
+
let configuredEnvs = await getAvailableEnvironments();
|
|
48247
48351
|
const needsSetup = targetEnv ? !configuredEnvs.includes(targetEnv) : configuredEnvs.length === 0;
|
|
48248
48352
|
if (needsSetup) {
|
|
48249
48353
|
const setupResult = await setupCredentials2(targetEnv);
|
|
@@ -48253,7 +48357,7 @@ async function ensureConfiguredEnvironments(targetEnv) {
|
|
|
48253
48357
|
if (setupResult === "error") {
|
|
48254
48358
|
return { status: "error" };
|
|
48255
48359
|
}
|
|
48256
|
-
configuredEnvs = await
|
|
48360
|
+
configuredEnvs = await getAvailableEnvironments();
|
|
48257
48361
|
const stillMissing = targetEnv ? !configuredEnvs.includes(targetEnv) : configuredEnvs.length === 0;
|
|
48258
48362
|
if (stillMissing) {
|
|
48259
48363
|
return { status: "error" };
|
|
@@ -52598,8 +52702,8 @@ async function installAndDisplay(options) {
|
|
|
52598
52702
|
|
|
52599
52703
|
// src/commands/init/lib/postInit.ts
|
|
52600
52704
|
async function ensureSyncEmail(targetEnv) {
|
|
52601
|
-
const
|
|
52602
|
-
if (
|
|
52705
|
+
const result = await loadCredentials(targetEnv);
|
|
52706
|
+
if (result.success && !result.credentials.email) {
|
|
52603
52707
|
return await updateEmail({ exitOnComplete: false, env: targetEnv });
|
|
52604
52708
|
}
|
|
52605
52709
|
return true;
|
|
@@ -76464,6 +76568,13 @@ var StringTimebackGrade4 = exports_external2.string().transform((value, ctx) =>
|
|
|
76464
76568
|
return exports_external2.NEVER;
|
|
76465
76569
|
}
|
|
76466
76570
|
const stripped = raw.replace(/\bgrade\b/g, "").replace(/(\d+)(st|nd|rd|th)\b/g, "$1").trim();
|
|
76571
|
+
if (stripped === "") {
|
|
76572
|
+
ctx.addIssue({
|
|
76573
|
+
code: "custom",
|
|
76574
|
+
message: "must be a valid Timeback grade"
|
|
76575
|
+
});
|
|
76576
|
+
return exports_external2.NEVER;
|
|
76577
|
+
}
|
|
76467
76578
|
if (stripped === "pre-k" || stripped === "pk") {
|
|
76468
76579
|
return -1;
|
|
76469
76580
|
}
|
|
@@ -78317,8 +78428,13 @@ var CredentialsSchema2 = exports_external2.object({
|
|
|
78317
78428
|
clientSecret: NonEmptyString4,
|
|
78318
78429
|
email: exports_external2.email("Valid email is required").optional()
|
|
78319
78430
|
});
|
|
78320
|
-
var
|
|
78321
|
-
|
|
78431
|
+
var StoredCredentialsSchema2 = exports_external2.object({
|
|
78432
|
+
clientId: NonEmptyString4.optional(),
|
|
78433
|
+
clientSecret: NonEmptyString4.optional(),
|
|
78434
|
+
email: exports_external2.email("Valid email is required").optional()
|
|
78435
|
+
}).refine((value) => value.email || value.clientId && value.clientSecret, "Saved credentials must include an email or a client ID/client secret pair").refine((value) => Boolean(value.clientId) === Boolean(value.clientSecret), "Saved credentials must include both client ID and client secret");
|
|
78436
|
+
var ClientIdSchema2 = exports_external2.string().min(1, "Client ID is required").max(128, "Client ID must be at most 128 characters").regex(/^[\w+]+$/, "Client ID must contain only letters, digits, underscores, or +");
|
|
78437
|
+
var ClientSecretSchema2 = exports_external2.string().min(24, "Client secret must be at least 24 characters").max(64, "Client secret must be at most 64 characters").regex(/^[\w+]+$/, "Client secret must contain only letters, digits, underscores, or +");
|
|
78322
78438
|
var MasteryTrackCredentialsSchema2 = exports_external2.object({
|
|
78323
78439
|
apiKey: NonEmptyString4,
|
|
78324
78440
|
email: exports_external2.email("Valid email is required")
|
|
@@ -78639,24 +78755,41 @@ async function writeCredentialsStore2(store) {
|
|
|
78639
78755
|
await writeFile3(CREDENTIALS_FILE2, JSON.stringify(cleaned, null, 2), { mode: 384 });
|
|
78640
78756
|
return true;
|
|
78641
78757
|
}
|
|
78642
|
-
|
|
78643
|
-
const store = await readCredentialsStore2();
|
|
78758
|
+
function getStoredCredentialsFromStore2(store, environment) {
|
|
78644
78759
|
const namespaced = store.timeback?.[environment];
|
|
78645
78760
|
if (namespaced) {
|
|
78646
|
-
const result =
|
|
78761
|
+
const result = StoredCredentialsSchema2.safeParse(namespaced);
|
|
78647
78762
|
if (result.success) {
|
|
78648
78763
|
return result.data;
|
|
78649
78764
|
}
|
|
78650
78765
|
}
|
|
78651
78766
|
const legacy = store[environment];
|
|
78652
78767
|
if (legacy) {
|
|
78653
|
-
const result =
|
|
78768
|
+
const result = StoredCredentialsSchema2.safeParse(legacy);
|
|
78654
78769
|
if (result.success) {
|
|
78655
78770
|
return result.data;
|
|
78656
78771
|
}
|
|
78657
78772
|
}
|
|
78658
78773
|
return null;
|
|
78659
78774
|
}
|
|
78775
|
+
async function getStoredCredentials2(environment) {
|
|
78776
|
+
const store = await readCredentialsStore2();
|
|
78777
|
+
return getStoredCredentialsFromStore2(store, environment);
|
|
78778
|
+
}
|
|
78779
|
+
function toCredentials2(stored) {
|
|
78780
|
+
if (stored?.clientId && stored.clientSecret) {
|
|
78781
|
+
return {
|
|
78782
|
+
clientId: stored.clientId,
|
|
78783
|
+
clientSecret: stored.clientSecret,
|
|
78784
|
+
email: stored.email
|
|
78785
|
+
};
|
|
78786
|
+
}
|
|
78787
|
+
return null;
|
|
78788
|
+
}
|
|
78789
|
+
async function getSavedCredentials2(environment) {
|
|
78790
|
+
const stored = await getStoredCredentials2(environment);
|
|
78791
|
+
return toCredentials2(stored);
|
|
78792
|
+
}
|
|
78660
78793
|
async function saveCredentials2(environment, credentials) {
|
|
78661
78794
|
const store = await readCredentialsStore2();
|
|
78662
78795
|
store.timeback = store.timeback ?? {};
|
|
@@ -78664,6 +78797,44 @@ async function saveCredentials2(environment, credentials) {
|
|
|
78664
78797
|
delete store[environment];
|
|
78665
78798
|
return writeCredentialsStore2(store);
|
|
78666
78799
|
}
|
|
78800
|
+
async function saveCredentialEmail2(environment, email32) {
|
|
78801
|
+
const store = await readCredentialsStore2();
|
|
78802
|
+
const existing = getStoredCredentialsFromStore2(store, environment);
|
|
78803
|
+
if (email32) {
|
|
78804
|
+
store.timeback = store.timeback ?? {};
|
|
78805
|
+
store.timeback[environment] = {
|
|
78806
|
+
...existing ?? {},
|
|
78807
|
+
email: email32
|
|
78808
|
+
};
|
|
78809
|
+
} else if (existing?.clientId && existing.clientSecret) {
|
|
78810
|
+
store.timeback = store.timeback ?? {};
|
|
78811
|
+
store.timeback[environment] = {
|
|
78812
|
+
clientId: existing.clientId,
|
|
78813
|
+
clientSecret: existing.clientSecret
|
|
78814
|
+
};
|
|
78815
|
+
} else {
|
|
78816
|
+
delete store.timeback?.[environment];
|
|
78817
|
+
if (store.timeback && Object.keys(store.timeback).length === 0) {
|
|
78818
|
+
delete store.timeback;
|
|
78819
|
+
}
|
|
78820
|
+
}
|
|
78821
|
+
delete store[environment];
|
|
78822
|
+
return writeCredentialsStore2(store);
|
|
78823
|
+
}
|
|
78824
|
+
async function getStoredCredentialEmail2(environment) {
|
|
78825
|
+
const stored = await getStoredCredentials2(environment);
|
|
78826
|
+
return stored?.email;
|
|
78827
|
+
}
|
|
78828
|
+
async function getEnvironmentsWithStoredEmail2() {
|
|
78829
|
+
const store = await readCredentialsStore2();
|
|
78830
|
+
const environments = [];
|
|
78831
|
+
for (const env22 of ENVIRONMENTS2) {
|
|
78832
|
+
if (getStoredCredentialsFromStore2(store, env22)?.email) {
|
|
78833
|
+
environments.push(env22);
|
|
78834
|
+
}
|
|
78835
|
+
}
|
|
78836
|
+
return environments;
|
|
78837
|
+
}
|
|
78667
78838
|
async function clearCredentials2(environment) {
|
|
78668
78839
|
const store = await readCredentialsStore2();
|
|
78669
78840
|
if (environment) {
|
|
@@ -78684,18 +78855,23 @@ async function getConfiguredEnvironments2() {
|
|
|
78684
78855
|
const store = await readCredentialsStore2();
|
|
78685
78856
|
const configured = [];
|
|
78686
78857
|
for (const env22 of ENVIRONMENTS2) {
|
|
78687
|
-
|
|
78688
|
-
if (namespaced && CredentialsSchema2.safeParse(namespaced).success) {
|
|
78689
|
-
configured.push(env22);
|
|
78690
|
-
continue;
|
|
78691
|
-
}
|
|
78692
|
-
const legacy = store[env22];
|
|
78693
|
-
if (legacy && CredentialsSchema2.safeParse(legacy).success) {
|
|
78858
|
+
if (toCredentials2(getStoredCredentialsFromStore2(store, env22))) {
|
|
78694
78859
|
configured.push(env22);
|
|
78695
78860
|
}
|
|
78696
78861
|
}
|
|
78697
78862
|
return configured;
|
|
78698
78863
|
}
|
|
78864
|
+
async function getAvailableEnvironments2() {
|
|
78865
|
+
const available = await getConfiguredEnvironments2();
|
|
78866
|
+
if (getEnvCredentials2()) {
|
|
78867
|
+
for (const env22 of ENVIRONMENTS2) {
|
|
78868
|
+
if (!available.includes(env22)) {
|
|
78869
|
+
available.push(env22);
|
|
78870
|
+
}
|
|
78871
|
+
}
|
|
78872
|
+
}
|
|
78873
|
+
return available;
|
|
78874
|
+
}
|
|
78699
78875
|
function getEnvCredentials2() {
|
|
78700
78876
|
const clientId = process.env.TIMEBACK_API_CLIENT_ID ?? process.env.TIMEBACK_CLIENT_ID;
|
|
78701
78877
|
const clientSecret = process.env.TIMEBACK_API_CLIENT_SECRET ?? process.env.TIMEBACK_CLIENT_SECRET;
|
|
@@ -78709,10 +78885,12 @@ function getEnvCredentials2() {
|
|
|
78709
78885
|
}
|
|
78710
78886
|
async function loadCredentials2(environment) {
|
|
78711
78887
|
const envCreds = getEnvCredentials2();
|
|
78888
|
+
const storedCreds = await getStoredCredentials2(environment);
|
|
78712
78889
|
if (envCreds) {
|
|
78713
|
-
|
|
78890
|
+
const merged = storedCreds?.email ? { ...envCreds, email: storedCreds.email } : envCreds;
|
|
78891
|
+
return { success: true, credentials: merged, source: "env" };
|
|
78714
78892
|
}
|
|
78715
|
-
const savedCreds =
|
|
78893
|
+
const savedCreds = toCredentials2(storedCreds);
|
|
78716
78894
|
if (savedCreds) {
|
|
78717
78895
|
return { success: true, credentials: savedCreds, source: "saved" };
|
|
78718
78896
|
}
|
|
@@ -78722,7 +78900,7 @@ async function loadCredentials2(environment) {
|
|
|
78722
78900
|
};
|
|
78723
78901
|
}
|
|
78724
78902
|
async function loadAllCredentials2() {
|
|
78725
|
-
const configuredEnvs = await
|
|
78903
|
+
const configuredEnvs = await getAvailableEnvironments2();
|
|
78726
78904
|
const credentials = {};
|
|
78727
78905
|
for (const env22 of configuredEnvs) {
|
|
78728
78906
|
const result = await loadCredentials2(env22);
|
|
@@ -80236,21 +80414,40 @@ async function addCredentials2(options = {}) {
|
|
|
80236
80414
|
async function listCredentials2(options = {}) {
|
|
80237
80415
|
const { exitOnComplete = true, inline = false } = options;
|
|
80238
80416
|
const lines = [];
|
|
80417
|
+
const envCreds = getEnvCredentials2();
|
|
80239
80418
|
let hasAny = false;
|
|
80419
|
+
let hasSaved = false;
|
|
80420
|
+
const hasEnv = Boolean(envCreds);
|
|
80240
80421
|
for (const env22 of ENVIRONMENTS2) {
|
|
80241
80422
|
const creds = await getSavedCredentials2(env22);
|
|
80242
|
-
if (creds) {
|
|
80423
|
+
if (creds && hasEnv) {
|
|
80424
|
+
lines.push(`${dim2("●")} ${env22}: ${creds.clientId}`);
|
|
80425
|
+
hasSaved = true;
|
|
80426
|
+
} else if (creds) {
|
|
80243
80427
|
lines.push(`${green2("●")} ${env22}: ${creds.clientId}`);
|
|
80244
|
-
|
|
80428
|
+
hasSaved = true;
|
|
80245
80429
|
} else {
|
|
80246
|
-
lines.push(`${dim2("○")} ${env22}:
|
|
80430
|
+
lines.push(`${dim2("○")} ${env22}: not configured`);
|
|
80247
80431
|
}
|
|
80248
80432
|
}
|
|
80433
|
+
hasAny = hasSaved || hasEnv;
|
|
80434
|
+
if (envCreds) {
|
|
80435
|
+
lines.push(`${green2("●")} env: ${envCreds.clientId} ${yellow2("[override]")}`);
|
|
80436
|
+
}
|
|
80249
80437
|
Me2(lines.join(`
|
|
80250
80438
|
`), "Configured environments");
|
|
80251
80439
|
if (hasAny) {
|
|
80252
|
-
|
|
80253
|
-
|
|
80440
|
+
const details = [];
|
|
80441
|
+
if (hasSaved) {
|
|
80442
|
+
details.push(`Credentials stored in ${blueBright2(underline2(getCredentialsPath2()))}`);
|
|
80443
|
+
}
|
|
80444
|
+
if (hasEnv) {
|
|
80445
|
+
details.push("Timeback env credentials are active");
|
|
80446
|
+
}
|
|
80447
|
+
if (details.length > 0 && !inline) {
|
|
80448
|
+
outro2.info(details.join(`
|
|
80449
|
+
`));
|
|
80450
|
+
}
|
|
80254
80451
|
} else {
|
|
80255
80452
|
const shouldAdd = await ye2({
|
|
80256
80453
|
message: "No credentials configured. Add now?"
|
|
@@ -80267,12 +80464,12 @@ async function listCredentials2(options = {}) {
|
|
|
80267
80464
|
}
|
|
80268
80465
|
async function updateEmail2(options = {}) {
|
|
80269
80466
|
const { exitOnComplete = true, inline = false } = options;
|
|
80270
|
-
const configuredEnvs = [
|
|
80271
|
-
|
|
80272
|
-
|
|
80273
|
-
|
|
80274
|
-
|
|
80275
|
-
|
|
80467
|
+
const configuredEnvs = [
|
|
80468
|
+
...new Set([
|
|
80469
|
+
...await getAvailableEnvironments2(),
|
|
80470
|
+
...await getEnvironmentsWithStoredEmail2()
|
|
80471
|
+
])
|
|
80472
|
+
];
|
|
80276
80473
|
if (configuredEnvs.length === 0) {
|
|
80277
80474
|
M22.warn("No credentials configured");
|
|
80278
80475
|
if (!inline)
|
|
@@ -80301,16 +80498,8 @@ async function updateEmail2(options = {}) {
|
|
|
80301
80498
|
}
|
|
80302
80499
|
targetEnv = selected;
|
|
80303
80500
|
}
|
|
80304
|
-
const
|
|
80305
|
-
|
|
80306
|
-
M22.error("Credentials not found");
|
|
80307
|
-
if (!inline)
|
|
80308
|
-
outro2.error("Credentials not found");
|
|
80309
|
-
if (exitOnComplete)
|
|
80310
|
-
process.exit(0);
|
|
80311
|
-
return;
|
|
80312
|
-
}
|
|
80313
|
-
const currentEmail = currentCreds.email;
|
|
80501
|
+
const currentCredsResult = await loadCredentials2(targetEnv);
|
|
80502
|
+
const currentEmail = currentCredsResult.success ? currentCredsResult.credentials.email : await getStoredCredentialEmail2(targetEnv);
|
|
80314
80503
|
const message = currentEmail ? `Email ${dim2(`(current: ${currentEmail})`)}` : `Email ${dim2("(not set)")}`;
|
|
80315
80504
|
const email32 = await he2({
|
|
80316
80505
|
message,
|
|
@@ -80333,7 +80522,23 @@ async function updateEmail2(options = {}) {
|
|
|
80333
80522
|
}
|
|
80334
80523
|
const normalized = email32 ? normalizeEmail2(email32) : undefined;
|
|
80335
80524
|
const emailUnchanged = (normalized ?? "") === (currentEmail ?? "");
|
|
80525
|
+
if (emailUnchanged) {
|
|
80526
|
+
if (!inline)
|
|
80527
|
+
outro2.info("Email unchanged");
|
|
80528
|
+
if (exitOnComplete)
|
|
80529
|
+
process.exit(0);
|
|
80530
|
+
return;
|
|
80531
|
+
}
|
|
80336
80532
|
if (normalized) {
|
|
80533
|
+
if (!currentCredsResult.success) {
|
|
80534
|
+
M22.error("Credentials required to set email");
|
|
80535
|
+
if (!inline)
|
|
80536
|
+
outro2.error("Credentials required to set email");
|
|
80537
|
+
if (exitOnComplete)
|
|
80538
|
+
process.exit(0);
|
|
80539
|
+
return;
|
|
80540
|
+
}
|
|
80541
|
+
const currentCreds = currentCredsResult.credentials;
|
|
80337
80542
|
const s = Y22();
|
|
80338
80543
|
s.start("Checking account...");
|
|
80339
80544
|
const result = await validateEmailWithTimeback2(targetEnv, currentCreds.clientId, currentCreds.clientSecret, normalized);
|
|
@@ -80354,11 +80559,8 @@ async function updateEmail2(options = {}) {
|
|
|
80354
80559
|
clientSecret: currentCreds.clientSecret,
|
|
80355
80560
|
email: normalized
|
|
80356
80561
|
});
|
|
80357
|
-
if (accountCreated
|
|
80358
|
-
await
|
|
80359
|
-
...currentCreds,
|
|
80360
|
-
email: normalized
|
|
80361
|
-
});
|
|
80562
|
+
if (accountCreated) {
|
|
80563
|
+
await saveCredentialEmail2(targetEnv, normalized);
|
|
80362
80564
|
M22.success(`Email saved for ${targetEnv}`);
|
|
80363
80565
|
}
|
|
80364
80566
|
if (!inline) {
|
|
@@ -80373,17 +80575,7 @@ async function updateEmail2(options = {}) {
|
|
|
80373
80575
|
return;
|
|
80374
80576
|
}
|
|
80375
80577
|
s.stop(green2("Account verified"));
|
|
80376
|
-
|
|
80377
|
-
if (!inline)
|
|
80378
|
-
outro2.info("Email unchanged");
|
|
80379
|
-
if (exitOnComplete)
|
|
80380
|
-
process.exit(0);
|
|
80381
|
-
return;
|
|
80382
|
-
}
|
|
80383
|
-
await saveCredentials2(targetEnv, {
|
|
80384
|
-
...currentCreds,
|
|
80385
|
-
email: normalized
|
|
80386
|
-
});
|
|
80578
|
+
await saveCredentialEmail2(targetEnv, normalized);
|
|
80387
80579
|
M22.success(`Email updated for ${targetEnv}`);
|
|
80388
80580
|
if (!inline)
|
|
80389
80581
|
outro2.success();
|
|
@@ -80391,10 +80583,7 @@ async function updateEmail2(options = {}) {
|
|
|
80391
80583
|
process.exit(0);
|
|
80392
80584
|
return;
|
|
80393
80585
|
}
|
|
80394
|
-
await
|
|
80395
|
-
...currentCreds,
|
|
80396
|
-
email: undefined
|
|
80397
|
-
});
|
|
80586
|
+
await saveCredentialEmail2(targetEnv, undefined);
|
|
80398
80587
|
if (!inline)
|
|
80399
80588
|
outro2.success(`Email cleared for ${targetEnv}`);
|
|
80400
80589
|
if (exitOnComplete)
|
|
@@ -80409,7 +80598,7 @@ async function removeCredentials2(options = {}) {
|
|
|
80409
80598
|
configuredEnvs.push(env22);
|
|
80410
80599
|
}
|
|
80411
80600
|
if (configuredEnvs.length === 0) {
|
|
80412
|
-
M22.warn("No credentials configured");
|
|
80601
|
+
M22.warn("No saved credentials configured");
|
|
80413
80602
|
if (exitOnComplete)
|
|
80414
80603
|
process.exit(0);
|
|
80415
80604
|
return;
|
|
@@ -80615,7 +80804,7 @@ async function promptNoConfig(credentials, configuredEnvs, opts = {}) {
|
|
|
80615
80804
|
}
|
|
80616
80805
|
async function resolveConfigSource(courseIds, opts, defaultEnvironment) {
|
|
80617
80806
|
const parserOpts = { playcademy: opts.playcademy };
|
|
80618
|
-
let configuredEnvs = await
|
|
80807
|
+
let configuredEnvs = await getAvailableEnvironments2();
|
|
80619
80808
|
let credentials = {};
|
|
80620
80809
|
if (courseIds.length > 0) {
|
|
80621
80810
|
if (configuredEnvs.length > 0) {
|
|
@@ -82945,8 +83134,8 @@ var cors = (options) => {
|
|
|
82945
83134
|
async function handleBootstrap(c, ctx) {
|
|
82946
83135
|
const { bootstrap } = c.get("services");
|
|
82947
83136
|
const env22 = c.get("env");
|
|
82948
|
-
const freshCredentials = await
|
|
82949
|
-
const email32 = freshCredentials
|
|
83137
|
+
const freshCredentials = await loadCredentials2(env22);
|
|
83138
|
+
const email32 = freshCredentials.success ? freshCredentials.credentials.email : undefined;
|
|
82950
83139
|
const courseIds = ctx.userConfig.courseIds[env22];
|
|
82951
83140
|
const result = await bootstrap.getBootstrap({ email: email32, courseIds });
|
|
82952
83141
|
return c.json(result);
|
|
@@ -83975,18 +84164,18 @@ class StatusService {
|
|
|
83975
84164
|
this.ctx = ctx;
|
|
83976
84165
|
}
|
|
83977
84166
|
async getStatus() {
|
|
83978
|
-
const configuredEnvironments = await
|
|
84167
|
+
const configuredEnvironments = await getAvailableEnvironments2();
|
|
83979
84168
|
const [stagingCreds, productionCreds] = await Promise.all([
|
|
83980
|
-
|
|
83981
|
-
|
|
84169
|
+
loadCredentials2("staging"),
|
|
84170
|
+
loadCredentials2("production")
|
|
83982
84171
|
]);
|
|
83983
|
-
const defaultCreds = this.ctx.defaultEnvironment === "staging" ? stagingCreds : this.ctx.defaultEnvironment === "production" ? productionCreds : null;
|
|
83984
|
-
const clientId = defaultCreds?.clientId ?? stagingCreds
|
|
84172
|
+
const defaultCreds = this.ctx.defaultEnvironment === "staging" ? stagingCreds.success ? stagingCreds.credentials : null : this.ctx.defaultEnvironment === "production" ? productionCreds.success ? productionCreds.credentials : null : null;
|
|
84173
|
+
const clientId = defaultCreds?.clientId ?? (stagingCreds.success ? stagingCreds.credentials.clientId : undefined) ?? (productionCreds.success ? productionCreds.credentials.clientId : undefined) ?? this.ctx.credentials.staging?.clientId ?? this.ctx.credentials.production?.clientId;
|
|
83985
84174
|
return {
|
|
83986
84175
|
config: this.ctx.userConfig,
|
|
83987
84176
|
environment: this.ctx.defaultEnvironment,
|
|
83988
84177
|
configuredEnvironments,
|
|
83989
|
-
hasEmail:
|
|
84178
|
+
hasEmail: stagingCreds.success && Boolean(stagingCreds.credentials.email) || productionCreds.success && Boolean(productionCreds.credentials.email),
|
|
83990
84179
|
clientId,
|
|
83991
84180
|
sensors: this.ctx.derivedSensors
|
|
83992
84181
|
};
|
|
@@ -84636,7 +84825,7 @@ async function launchServer(serverConfig, userConfig, credentials, env22, opts,
|
|
|
84636
84825
|
}
|
|
84637
84826
|
async function handleCourseIdsCase(courseIds, opts, serverConfig) {
|
|
84638
84827
|
const env22 = opts.env ?? await promptEnvironmentForCourseIds(courseIds.length);
|
|
84639
|
-
let configuredEnvs = await
|
|
84828
|
+
let configuredEnvs = await getAvailableEnvironments2();
|
|
84640
84829
|
let credentials = configuredEnvs.length > 0 ? await loadAllCredentials2() : {};
|
|
84641
84830
|
const resolvedResult = await resolveConfigSource(courseIds, opts, env22);
|
|
84642
84831
|
if (!resolvedResult) {
|
|
@@ -84688,7 +84877,7 @@ async function handleConfigFileCase(userConfig, configPath, opts, serverConfig)
|
|
|
84688
84877
|
await launchServer(serverConfig, userConfig, credentials, env22, opts, configPath);
|
|
84689
84878
|
}
|
|
84690
84879
|
async function handleImportFlowCase(opts, serverConfig) {
|
|
84691
|
-
let configuredEnvs = await
|
|
84880
|
+
let configuredEnvs = await getAvailableEnvironments2();
|
|
84692
84881
|
let credentials = {};
|
|
84693
84882
|
let selectedEnv;
|
|
84694
84883
|
if (configuredEnvs.length === 0) {
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
"$ref": "#/definitions/__schema22"
|
|
16
16
|
},
|
|
17
17
|
"sensor": {
|
|
18
|
-
"$ref": "#/definitions/
|
|
18
|
+
"$ref": "#/definitions/__schema38"
|
|
19
19
|
},
|
|
20
20
|
"launchUrl": {
|
|
21
|
-
"$ref": "#/definitions/
|
|
21
|
+
"$ref": "#/definitions/__schema39"
|
|
22
22
|
},
|
|
23
23
|
"studio": {
|
|
24
|
-
"$ref": "#/definitions/
|
|
24
|
+
"$ref": "#/definitions/__schema40"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"required": ["name", "courses"],
|
|
@@ -282,16 +282,16 @@
|
|
|
282
282
|
"$ref": "#/definitions/__schema24"
|
|
283
283
|
},
|
|
284
284
|
"ids": {
|
|
285
|
-
"$ref": "#/definitions/
|
|
285
|
+
"$ref": "#/definitions/__schema26"
|
|
286
286
|
},
|
|
287
287
|
"sensor": {
|
|
288
|
-
"$ref": "#/definitions/
|
|
288
|
+
"$ref": "#/definitions/__schema29"
|
|
289
289
|
},
|
|
290
290
|
"launchUrl": {
|
|
291
|
-
"$ref": "#/definitions/
|
|
291
|
+
"$ref": "#/definitions/__schema30"
|
|
292
292
|
},
|
|
293
293
|
"overrides": {
|
|
294
|
-
"$ref": "#/definitions/
|
|
294
|
+
"$ref": "#/definitions/__schema31"
|
|
295
295
|
}
|
|
296
296
|
},
|
|
297
297
|
"required": ["subject"],
|
|
@@ -325,121 +325,88 @@
|
|
|
325
325
|
"__schema24": {
|
|
326
326
|
"allOf": [
|
|
327
327
|
{
|
|
328
|
+
"allOf": [
|
|
329
|
+
{
|
|
330
|
+
"$ref": "#/definitions/__schema25"
|
|
331
|
+
}
|
|
332
|
+
],
|
|
328
333
|
"$ref": "#/definitions/TimebackGrade"
|
|
329
334
|
}
|
|
330
335
|
]
|
|
331
336
|
},
|
|
332
337
|
"__schema25": {
|
|
333
|
-
"type": "number",
|
|
334
|
-
"const": -1
|
|
335
|
-
},
|
|
336
|
-
"__schema26": {
|
|
337
|
-
"type": "number",
|
|
338
|
-
"const": 0
|
|
339
|
-
},
|
|
340
|
-
"__schema27": {
|
|
341
|
-
"type": "number",
|
|
342
|
-
"const": 1
|
|
343
|
-
},
|
|
344
|
-
"__schema28": {
|
|
345
|
-
"type": "number",
|
|
346
|
-
"const": 2
|
|
347
|
-
},
|
|
348
|
-
"__schema29": {
|
|
349
|
-
"type": "number",
|
|
350
|
-
"const": 3
|
|
351
|
-
},
|
|
352
|
-
"__schema30": {
|
|
353
|
-
"type": "number",
|
|
354
|
-
"const": 4
|
|
355
|
-
},
|
|
356
|
-
"__schema31": {
|
|
357
|
-
"type": "number",
|
|
358
|
-
"const": 5
|
|
359
|
-
},
|
|
360
|
-
"__schema32": {
|
|
361
|
-
"type": "number",
|
|
362
|
-
"const": 6
|
|
363
|
-
},
|
|
364
|
-
"__schema33": {
|
|
365
|
-
"type": "number",
|
|
366
|
-
"const": 7
|
|
367
|
-
},
|
|
368
|
-
"__schema34": {
|
|
369
|
-
"type": "number",
|
|
370
|
-
"const": 8
|
|
371
|
-
},
|
|
372
|
-
"__schema35": {
|
|
373
|
-
"type": "number",
|
|
374
|
-
"const": 9
|
|
375
|
-
},
|
|
376
|
-
"__schema36": {
|
|
377
|
-
"type": "number",
|
|
378
|
-
"const": 10
|
|
379
|
-
},
|
|
380
|
-
"__schema37": {
|
|
381
|
-
"type": "number",
|
|
382
|
-
"const": 11
|
|
383
|
-
},
|
|
384
|
-
"__schema38": {
|
|
385
|
-
"type": "number",
|
|
386
|
-
"const": 12
|
|
387
|
-
},
|
|
388
|
-
"__schema39": {
|
|
389
|
-
"type": "number",
|
|
390
|
-
"const": 13
|
|
391
|
-
},
|
|
392
|
-
"TimebackGrade": {
|
|
393
338
|
"anyOf": [
|
|
394
339
|
{
|
|
395
|
-
"
|
|
340
|
+
"type": "number",
|
|
341
|
+
"const": -1
|
|
396
342
|
},
|
|
397
343
|
{
|
|
398
|
-
"
|
|
344
|
+
"type": "number",
|
|
345
|
+
"const": 0
|
|
399
346
|
},
|
|
400
347
|
{
|
|
401
|
-
"
|
|
348
|
+
"type": "number",
|
|
349
|
+
"const": 1
|
|
402
350
|
},
|
|
403
351
|
{
|
|
404
|
-
"
|
|
352
|
+
"type": "number",
|
|
353
|
+
"const": 2
|
|
405
354
|
},
|
|
406
355
|
{
|
|
407
|
-
"
|
|
356
|
+
"type": "number",
|
|
357
|
+
"const": 3
|
|
408
358
|
},
|
|
409
359
|
{
|
|
410
|
-
"
|
|
360
|
+
"type": "number",
|
|
361
|
+
"const": 4
|
|
411
362
|
},
|
|
412
363
|
{
|
|
413
|
-
"
|
|
364
|
+
"type": "number",
|
|
365
|
+
"const": 5
|
|
414
366
|
},
|
|
415
367
|
{
|
|
416
|
-
"
|
|
368
|
+
"type": "number",
|
|
369
|
+
"const": 6
|
|
417
370
|
},
|
|
418
371
|
{
|
|
419
|
-
"
|
|
372
|
+
"type": "number",
|
|
373
|
+
"const": 7
|
|
420
374
|
},
|
|
421
375
|
{
|
|
422
|
-
"
|
|
376
|
+
"type": "number",
|
|
377
|
+
"const": 8
|
|
423
378
|
},
|
|
424
379
|
{
|
|
425
|
-
"
|
|
380
|
+
"type": "number",
|
|
381
|
+
"const": 9
|
|
426
382
|
},
|
|
427
383
|
{
|
|
428
|
-
"
|
|
384
|
+
"type": "number",
|
|
385
|
+
"const": 10
|
|
429
386
|
},
|
|
430
387
|
{
|
|
431
|
-
"
|
|
388
|
+
"type": "number",
|
|
389
|
+
"const": 11
|
|
432
390
|
},
|
|
433
391
|
{
|
|
434
|
-
"
|
|
392
|
+
"type": "number",
|
|
393
|
+
"const": 12
|
|
435
394
|
},
|
|
436
395
|
{
|
|
437
|
-
"
|
|
396
|
+
"type": "number",
|
|
397
|
+
"const": 13
|
|
438
398
|
}
|
|
439
|
-
]
|
|
440
|
-
"description": "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)"
|
|
399
|
+
]
|
|
441
400
|
},
|
|
442
|
-
"
|
|
401
|
+
"TimebackGrade": {
|
|
402
|
+
"description": "Grade level (-1 = Pre-K, 0 = K, 1-12 = grades, 13 = AP)",
|
|
403
|
+
"allOf": [
|
|
404
|
+
{
|
|
405
|
+
"$ref": "#/definitions/__schema25"
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
},
|
|
409
|
+
"__schema26": {
|
|
443
410
|
"anyOf": [
|
|
444
411
|
{
|
|
445
412
|
"$ref": "#/definitions/CourseIds"
|
|
@@ -453,34 +420,34 @@
|
|
|
453
420
|
"type": "object",
|
|
454
421
|
"properties": {
|
|
455
422
|
"staging": {
|
|
456
|
-
"$ref": "#/definitions/
|
|
423
|
+
"$ref": "#/definitions/__schema27"
|
|
457
424
|
},
|
|
458
425
|
"production": {
|
|
459
|
-
"$ref": "#/definitions/
|
|
426
|
+
"$ref": "#/definitions/__schema28"
|
|
460
427
|
}
|
|
461
428
|
},
|
|
462
429
|
"additionalProperties": false,
|
|
463
430
|
"description": "Environment-specific course IDs (populated by sync)"
|
|
464
431
|
},
|
|
465
|
-
"
|
|
432
|
+
"__schema27": {
|
|
466
433
|
"type": "string",
|
|
467
434
|
"description": "Course ID in staging environment"
|
|
468
435
|
},
|
|
469
|
-
"
|
|
436
|
+
"__schema28": {
|
|
470
437
|
"type": "string",
|
|
471
438
|
"description": "Course ID in production environment"
|
|
472
439
|
},
|
|
473
|
-
"
|
|
440
|
+
"__schema29": {
|
|
474
441
|
"type": "string",
|
|
475
442
|
"format": "uri",
|
|
476
443
|
"description": "Caliper sensor endpoint URL for this course"
|
|
477
444
|
},
|
|
478
|
-
"
|
|
445
|
+
"__schema30": {
|
|
479
446
|
"type": "string",
|
|
480
447
|
"format": "uri",
|
|
481
448
|
"description": "LTI launch URL for this course"
|
|
482
449
|
},
|
|
483
|
-
"
|
|
450
|
+
"__schema31": {
|
|
484
451
|
"allOf": [
|
|
485
452
|
{
|
|
486
453
|
"$ref": "#/definitions/CourseOverrides"
|
|
@@ -491,16 +458,16 @@
|
|
|
491
458
|
"type": "object",
|
|
492
459
|
"properties": {
|
|
493
460
|
"staging": {
|
|
494
|
-
"$ref": "#/definitions/
|
|
461
|
+
"$ref": "#/definitions/__schema32"
|
|
495
462
|
},
|
|
496
463
|
"production": {
|
|
497
|
-
"$ref": "#/definitions/
|
|
464
|
+
"$ref": "#/definitions/__schema37"
|
|
498
465
|
}
|
|
499
466
|
},
|
|
500
467
|
"additionalProperties": false,
|
|
501
468
|
"description": "Per-environment course overrides"
|
|
502
469
|
},
|
|
503
|
-
"
|
|
470
|
+
"__schema32": {
|
|
504
471
|
"description": "Overrides for staging environment",
|
|
505
472
|
"allOf": [
|
|
506
473
|
{
|
|
@@ -508,21 +475,21 @@
|
|
|
508
475
|
}
|
|
509
476
|
]
|
|
510
477
|
},
|
|
511
|
-
"
|
|
478
|
+
"__schema33": {
|
|
512
479
|
"type": "string",
|
|
513
480
|
"description": "Course level for this environment"
|
|
514
481
|
},
|
|
515
|
-
"
|
|
482
|
+
"__schema34": {
|
|
516
483
|
"type": "string",
|
|
517
484
|
"format": "uri",
|
|
518
485
|
"description": "Caliper sensor endpoint URL for this environment"
|
|
519
486
|
},
|
|
520
|
-
"
|
|
487
|
+
"__schema35": {
|
|
521
488
|
"type": "string",
|
|
522
489
|
"format": "uri",
|
|
523
490
|
"description": "LTI launch URL for this environment"
|
|
524
491
|
},
|
|
525
|
-
"
|
|
492
|
+
"__schema36": {
|
|
526
493
|
"allOf": [
|
|
527
494
|
{
|
|
528
495
|
"$ref": "#/definitions/CourseMetadata"
|
|
@@ -533,22 +500,22 @@
|
|
|
533
500
|
"type": "object",
|
|
534
501
|
"properties": {
|
|
535
502
|
"level": {
|
|
536
|
-
"$ref": "#/definitions/
|
|
503
|
+
"$ref": "#/definitions/__schema33"
|
|
537
504
|
},
|
|
538
505
|
"sensor": {
|
|
539
|
-
"$ref": "#/definitions/
|
|
506
|
+
"$ref": "#/definitions/__schema34"
|
|
540
507
|
},
|
|
541
508
|
"launchUrl": {
|
|
542
|
-
"$ref": "#/definitions/
|
|
509
|
+
"$ref": "#/definitions/__schema35"
|
|
543
510
|
},
|
|
544
511
|
"metadata": {
|
|
545
|
-
"$ref": "#/definitions/
|
|
512
|
+
"$ref": "#/definitions/__schema36"
|
|
546
513
|
}
|
|
547
514
|
},
|
|
548
515
|
"additionalProperties": false,
|
|
549
516
|
"description": "Environment-specific course overrides (non-identity fields)"
|
|
550
517
|
},
|
|
551
|
-
"
|
|
518
|
+
"__schema37": {
|
|
552
519
|
"description": "Overrides for production environment",
|
|
553
520
|
"allOf": [
|
|
554
521
|
{
|
|
@@ -556,27 +523,27 @@
|
|
|
556
523
|
}
|
|
557
524
|
]
|
|
558
525
|
},
|
|
559
|
-
"
|
|
526
|
+
"__schema38": {
|
|
560
527
|
"type": "string",
|
|
561
528
|
"format": "uri",
|
|
562
529
|
"description": "Default Caliper sensor endpoint URL for all courses"
|
|
563
530
|
},
|
|
564
|
-
"
|
|
531
|
+
"__schema39": {
|
|
565
532
|
"type": "string",
|
|
566
533
|
"format": "uri",
|
|
567
534
|
"description": "Default LTI launch URL for all courses"
|
|
568
535
|
},
|
|
569
|
-
"
|
|
536
|
+
"__schema40": {
|
|
570
537
|
"type": "object",
|
|
571
538
|
"properties": {
|
|
572
539
|
"telemetry": {
|
|
573
|
-
"$ref": "#/definitions/
|
|
540
|
+
"$ref": "#/definitions/__schema41"
|
|
574
541
|
}
|
|
575
542
|
},
|
|
576
543
|
"additionalProperties": false,
|
|
577
544
|
"description": "Studio-specific configuration"
|
|
578
545
|
},
|
|
579
|
-
"
|
|
546
|
+
"__schema41": {
|
|
580
547
|
"default": true,
|
|
581
548
|
"type": "boolean",
|
|
582
549
|
"description": "Enable anonymous usage telemetry for Studio (default: true)"
|
|
@@ -597,13 +564,13 @@
|
|
|
597
564
|
"$ref": "#/definitions/__schema22"
|
|
598
565
|
},
|
|
599
566
|
"sensor": {
|
|
600
|
-
"$ref": "#/definitions/
|
|
567
|
+
"$ref": "#/definitions/__schema38"
|
|
601
568
|
},
|
|
602
569
|
"launchUrl": {
|
|
603
|
-
"$ref": "#/definitions/
|
|
570
|
+
"$ref": "#/definitions/__schema39"
|
|
604
571
|
},
|
|
605
572
|
"studio": {
|
|
606
|
-
"$ref": "#/definitions/
|
|
573
|
+
"$ref": "#/definitions/__schema40"
|
|
607
574
|
}
|
|
608
575
|
},
|
|
609
576
|
"required": ["name", "courses"],
|