timeback-studio 0.1.5 → 0.1.7

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/bin.js CHANGED
@@ -2950,6 +2950,11 @@ ${t}
2950
2950
  ${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
2951
2951
  ${c}
2952
2952
  ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
2953
+ `);
2954
+ };
2955
+ var xe = (t = "") => {
2956
+ process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
2957
+
2953
2958
  `);
2954
2959
  };
2955
2960
  var Ie = (t = "") => {
@@ -16695,7 +16700,7 @@ function intro(title) {
16695
16700
  }
16696
16701
  var outro = {
16697
16702
  success: (message = "Done") => Se(green(message)),
16698
- cancelled: () => Se(dim("Cancelled")),
16703
+ cancelled: () => xe(dim("Cancelled")),
16699
16704
  error: (message) => Se(red(message)),
16700
16705
  warn: (message) => Se(yellow(message)),
16701
16706
  info: (message) => Se(dim(message))
@@ -16795,8 +16800,8 @@ async function getConfiguredEnvironments() {
16795
16800
  return configured;
16796
16801
  }
16797
16802
  function getEnvCredentials() {
16798
- const clientId = process.env.TIMEBACK_CLIENT_ID;
16799
- const clientSecret = process.env.TIMEBACK_CLIENT_SECRET;
16803
+ const clientId = process.env.TIMEBACK_API_CLIENT_ID ?? process.env.TIMEBACK_CLIENT_ID;
16804
+ const clientSecret = process.env.TIMEBACK_API_CLIENT_SECRET ?? process.env.TIMEBACK_CLIENT_SECRET;
16800
16805
  if (clientId && clientSecret) {
16801
16806
  const result = CredentialsSchema.safeParse({ clientId, clientSecret });
16802
16807
  if (result.success) {
@@ -16840,19 +16845,23 @@ async function validateEmailWithTimeback(environment, clientId, clientSecret, em
16840
16845
  });
16841
16846
  try {
16842
16847
  const page = await client.oneroster.users.list({
16843
- where: { email: email3 },
16848
+ where: {
16849
+ email: email3,
16850
+ status: "active"
16851
+ },
16844
16852
  limit: 1
16845
16853
  });
16846
16854
  if (page.data.length === 0) {
16847
16855
  return {
16848
16856
  valid: false,
16857
+ reason: "not_found",
16849
16858
  error: `No user found with email "${email3}" in ${environment}`
16850
16859
  };
16851
16860
  }
16852
16861
  return { valid: true };
16853
16862
  } catch (error48) {
16854
16863
  const message = error48 instanceof Error ? error48.message : "Unknown error";
16855
- return { valid: false, error: `Failed to validate email: ${message}` };
16864
+ return { valid: false, reason: "api_error", error: `Failed to validate email: ${message}` };
16856
16865
  }
16857
16866
  }
16858
16867
 
@@ -16868,7 +16877,7 @@ async function promptForCredentials(environment) {
16868
16877
  }
16869
16878
  });
16870
16879
  if (isCancelled(clientId))
16871
- return null;
16880
+ return { status: "cancelled" };
16872
16881
  const clientSecret = await ge({
16873
16882
  message: `Client Secret ${dim(`(${environment})`)}`,
16874
16883
  validate: (value) => {
@@ -16878,7 +16887,7 @@ async function promptForCredentials(environment) {
16878
16887
  }
16879
16888
  });
16880
16889
  if (isCancelled(clientSecret))
16881
- return null;
16890
+ return { status: "cancelled" };
16882
16891
  const email3 = await he({
16883
16892
  message: `Your email ${dim("(for fetching your OneRoster profile)")}`,
16884
16893
  placeholder: "you@example.com",
@@ -16891,33 +16900,47 @@ async function promptForCredentials(environment) {
16891
16900
  }
16892
16901
  });
16893
16902
  if (isCancelled(email3))
16894
- return null;
16903
+ return { status: "cancelled" };
16895
16904
  if (email3) {
16896
16905
  const s = Y2();
16897
16906
  s.start("Validating email...");
16898
16907
  const result = await validateEmailWithTimeback(environment, clientId, clientSecret, email3);
16899
16908
  if (!result.valid) {
16900
- s.stop(red("Email validation failed"));
16901
- M2.error(result.error ?? "Unknown error");
16909
+ const errorMsg = result.error ?? "Email validation failed";
16910
+ s.stop(red(errorMsg));
16902
16911
  M2.info("Please contact a Timeback admin to set up your account.");
16903
- return null;
16912
+ return {
16913
+ status: "error",
16914
+ error: errorMsg
16915
+ };
16904
16916
  }
16905
16917
  s.stop(green("Email validated"));
16906
16918
  }
16907
- return { clientId, clientSecret, email: email3 || undefined };
16919
+ return {
16920
+ status: "ok",
16921
+ credentials: { clientId, clientSecret, email: email3 || undefined }
16922
+ };
16908
16923
  }
16909
16924
  async function ensureCredentials(options) {
16910
16925
  const { env: env2, credentials, introTitle = "Timeback", skipIntro = false } = options;
16911
16926
  const existing = credentials[env2];
16912
- if (existing)
16913
- return existing;
16927
+ if (existing) {
16928
+ return { status: "ok", credentials: existing, source: "existing" };
16929
+ }
16914
16930
  if (!skipIntro) {
16915
16931
  intro(introTitle);
16916
16932
  }
16917
16933
  Me(`No credentials configured for ${env2}.`, "Credential setup required");
16918
- const newCreds = await promptForCredentials(env2);
16919
- if (!newCreds)
16920
- return null;
16934
+ const promptResult = await promptForCredentials(env2);
16935
+ if (promptResult.status === "cancelled") {
16936
+ outro.cancelled();
16937
+ return { status: "cancelled" };
16938
+ }
16939
+ if (promptResult.status === "error") {
16940
+ outro.error("Credential setup failed");
16941
+ return { status: "error", error: promptResult.error };
16942
+ }
16943
+ const newCreds = promptResult.credentials;
16921
16944
  const saved = await saveCredentials(env2, newCreds);
16922
16945
  if (saved) {
16923
16946
  M2.success(`${env2} credentials saved`);
@@ -16926,7 +16949,7 @@ async function ensureCredentials(options) {
16926
16949
  M2.warn(`Credentials not saved`);
16927
16950
  }
16928
16951
  credentials[env2] = newCreds;
16929
- return newCreds;
16952
+ return { status: "ok", credentials: newCreds, source: "prompted" };
16930
16953
  }
16931
16954
  // ../internal/cli-infra/src/config/playcademy.ts
16932
16955
  var FILE_PATTERNS = ["playcademy.config.ts", "playcademy.config.js", "playcademy.config.json"];
@@ -17140,6 +17163,8 @@ var ActivityCompletedInput = exports_external.object({
17140
17163
  metricsId: exports_external.string().optional(),
17141
17164
  id: exports_external.string().optional(),
17142
17165
  extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
17166
+ edApp: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional(),
17167
+ session: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional(),
17143
17168
  attempt: exports_external.number().int().min(1).optional(),
17144
17169
  generatedExtensions: exports_external.object({
17145
17170
  pctCompleteApp: exports_external.number().optional()
@@ -17152,7 +17177,9 @@ var TimeSpentInput = exports_external.object({
17152
17177
  eventTime: IsoDateTimeString.optional(),
17153
17178
  metricsId: exports_external.string().optional(),
17154
17179
  id: exports_external.string().optional(),
17155
- extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
17180
+ extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
17181
+ edApp: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional(),
17182
+ session: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional()
17156
17183
  }).strict();
17157
17184
  var TimebackEvent = exports_external.union([TimebackActivityEvent, TimebackTimeSpentEvent]);
17158
17185
  var CaliperEnvelope = exports_external.object({
@@ -17342,7 +17369,7 @@ var TimebackConfig = exports_external.object({
17342
17369
  path: ["courses"]
17343
17370
  });
17344
17371
  // ../types/src/zod/edubridge.ts
17345
- var EdubridgeDateString = IsoDateTimeString;
17372
+ var EdubridgeDateString = exports_external.union([IsoDateTimeString, IsoDateString]);
17346
17373
  var EduBridgeEnrollment = exports_external.object({
17347
17374
  id: exports_external.string(),
17348
17375
  role: exports_external.string(),
@@ -19408,8 +19435,8 @@ async function addCredentials(options = {}) {
19408
19435
  }
19409
19436
  isOverwriting = true;
19410
19437
  }
19411
- const creds = await promptForCredentials(env2);
19412
- if (creds === null) {
19438
+ const result = await promptForCredentials(env2);
19439
+ if (result.status === "cancelled") {
19413
19440
  if (!inline) {
19414
19441
  if (isOverwriting) {
19415
19442
  outro.info("Existing credentials unchanged");
@@ -19417,11 +19444,21 @@ async function addCredentials(options = {}) {
19417
19444
  outro.cancelled();
19418
19445
  }
19419
19446
  }
19420
- if (exitOnComplete)
19447
+ if (exitOnComplete) {
19421
19448
  process.exit(0);
19449
+ }
19450
+ return;
19451
+ }
19452
+ if (result.status === "error") {
19453
+ if (!inline) {
19454
+ outro.error("Credential setup failed");
19455
+ }
19456
+ if (exitOnComplete) {
19457
+ process.exit(1);
19458
+ }
19422
19459
  return;
19423
19460
  }
19424
- await saveCredentials(env2, creds);
19461
+ await saveCredentials(env2, result.credentials);
19425
19462
  M2.success(`${env2} credentials saved`);
19426
19463
  savedCount++;
19427
19464
  }
@@ -19433,6 +19470,184 @@ async function addCredentials(options = {}) {
19433
19470
  if (exitOnComplete)
19434
19471
  process.exit(0);
19435
19472
  }
19473
+ // src/cli/commands/credentials/create-account.ts
19474
+ import { randomUUID } from "node:crypto";
19475
+ import { TimebackClient as TimebackClient2 } from "@timeback/core";
19476
+ async function promptName(label) {
19477
+ const value = await he({
19478
+ message: label,
19479
+ placeholder: "Enter name",
19480
+ validate: (v2) => {
19481
+ if (!v2?.trim())
19482
+ return `${label} is required`;
19483
+ }
19484
+ });
19485
+ if (isCancelled(value))
19486
+ return null;
19487
+ return value.trim();
19488
+ }
19489
+ async function searchOrganizations(client, query) {
19490
+ const allOrgs = await client.oneroster.orgs.listAll({
19491
+ where: { status: "active" },
19492
+ max: 100
19493
+ });
19494
+ if (!query.trim())
19495
+ return allOrgs;
19496
+ const lowerQuery = query.toLowerCase().trim();
19497
+ return allOrgs.filter((org) => org.name?.toLowerCase().includes(lowerQuery));
19498
+ }
19499
+ async function searchForOrganization(client) {
19500
+ const query = await he({
19501
+ message: "Search for organization",
19502
+ placeholder: "Enter organization name to search"
19503
+ });
19504
+ if (isCancelled(query))
19505
+ return null;
19506
+ const s = Y2();
19507
+ s.start("Searching organizations...");
19508
+ let results;
19509
+ try {
19510
+ results = await searchOrganizations(client, query);
19511
+ s.stop(green(`Found ${results.length} result${results.length === 1 ? "" : "s"}`));
19512
+ } catch (error48) {
19513
+ s.stop(red("Failed to search organizations"));
19514
+ M2.error(error48 instanceof Error ? error48.message : "Unknown error");
19515
+ return null;
19516
+ }
19517
+ if (results.length === 0) {
19518
+ M2.warn("No organizations found matching your search");
19519
+ return promptOrganization(client);
19520
+ }
19521
+ const validResults = results.filter((org) => org.sourcedId);
19522
+ if (validResults.length === 0) {
19523
+ M2.warn("No valid organizations found (missing IDs)");
19524
+ return promptOrganization(client);
19525
+ }
19526
+ const options = validResults.map((org) => ({
19527
+ value: org.sourcedId,
19528
+ label: org.name ?? "Unnamed Organization"
19529
+ }));
19530
+ options.push({ value: "__back__", label: `${dim("←")} Back to options` });
19531
+ const selection = await ve({
19532
+ message: "Select an organization",
19533
+ options
19534
+ });
19535
+ if (isCancelled(selection))
19536
+ return null;
19537
+ if (selection === "__back__") {
19538
+ return promptOrganization(client);
19539
+ }
19540
+ return validResults.find((org) => org.sourcedId === selection) ?? null;
19541
+ }
19542
+ async function promptOrganization(client) {
19543
+ const action = await ve({
19544
+ message: "Organization",
19545
+ options: [
19546
+ { value: "search", label: "Search for existing organization" },
19547
+ { value: "create", label: "Create new organization" }
19548
+ ]
19549
+ });
19550
+ if (isCancelled(action))
19551
+ return null;
19552
+ if (action === "create") {
19553
+ return createNewOrganization(client);
19554
+ }
19555
+ return searchForOrganization(client);
19556
+ }
19557
+ async function createNewOrganization(client) {
19558
+ const name = await he({
19559
+ message: "Organization name",
19560
+ placeholder: "Enter organization name",
19561
+ validate: (v2) => {
19562
+ if (!v2?.trim())
19563
+ return "Organization name is required";
19564
+ }
19565
+ });
19566
+ if (isCancelled(name))
19567
+ return null;
19568
+ const s = Y2();
19569
+ s.start("Creating organization...");
19570
+ const sourcedId = randomUUID();
19571
+ try {
19572
+ await client.oneroster.orgs.create({
19573
+ sourcedId,
19574
+ name: name.trim(),
19575
+ type: "school",
19576
+ status: "active"
19577
+ });
19578
+ const organization = await client.oneroster.orgs.get(sourcedId);
19579
+ s.stop(green(`Organization "${name}" created`));
19580
+ return organization;
19581
+ } catch (error48) {
19582
+ s.stop(red("Failed to create organization"));
19583
+ M2.error(error48 instanceof Error ? error48.message : "Unknown error");
19584
+ return null;
19585
+ }
19586
+ }
19587
+ async function createUser(client, email3, givenName, familyName, organizationId) {
19588
+ const s = Y2();
19589
+ s.start("Creating account...");
19590
+ const sourcedId = randomUUID();
19591
+ try {
19592
+ await client.oneroster.users.create({
19593
+ sourcedId,
19594
+ givenName,
19595
+ familyName,
19596
+ email: email3.toLowerCase(),
19597
+ enabledUser: true,
19598
+ status: "active",
19599
+ roles: [
19600
+ {
19601
+ roleType: "primary",
19602
+ role: "administrator",
19603
+ org: { sourcedId: organizationId }
19604
+ }
19605
+ ]
19606
+ });
19607
+ const user = await client.oneroster.users.get(sourcedId);
19608
+ s.stop(green("Account created successfully"));
19609
+ return user;
19610
+ } catch (error48) {
19611
+ s.stop(red("Failed to create account"));
19612
+ M2.error(error48 instanceof Error ? error48.message : "Unknown error");
19613
+ return null;
19614
+ }
19615
+ }
19616
+ async function createAccountFlow(options) {
19617
+ const { environment, clientId, clientSecret, email: email3 } = options;
19618
+ M2.info("");
19619
+ M2.info(`No account found for ${dim(email3)} in ${environment}`);
19620
+ const shouldCreate = await ye({
19621
+ message: "Would you like to create a new account?",
19622
+ initialValue: true
19623
+ });
19624
+ if (isCancelled(shouldCreate)) {
19625
+ return { success: false };
19626
+ }
19627
+ if (!shouldCreate) {
19628
+ return { success: false, declined: true };
19629
+ }
19630
+ const client = new TimebackClient2({
19631
+ env: environment,
19632
+ auth: { clientId, clientSecret }
19633
+ });
19634
+ const givenName = await promptName("First name");
19635
+ if (!givenName)
19636
+ return { success: false };
19637
+ const familyName = await promptName("Last name");
19638
+ if (!familyName)
19639
+ return { success: false };
19640
+ const organization = await promptOrganization(client);
19641
+ if (!organization?.sourcedId)
19642
+ return { success: false };
19643
+ const user = await createUser(client, email3, givenName, familyName, organization.sourcedId);
19644
+ if (!user) {
19645
+ return { success: false };
19646
+ }
19647
+ M2.success(`Account created for ${user.givenName} ${user.familyName}`);
19648
+ return { success: true };
19649
+ }
19650
+
19436
19651
  // src/cli/commands/credentials/email.ts
19437
19652
  async function updateEmail(options = {}) {
19438
19653
  const { exitOnComplete = true, inline = false } = options;
@@ -19501,32 +19716,58 @@ async function updateEmail(options = {}) {
19501
19716
  return;
19502
19717
  }
19503
19718
  const emailUnchanged = email3 === (currentEmail ?? "");
19504
- if (emailUnchanged) {
19505
- if (!inline)
19506
- outro.info("Email unchanged");
19507
- if (exitOnComplete)
19508
- process.exit(0);
19509
- return;
19510
- }
19511
19719
  if (email3) {
19512
19720
  const s = Y2();
19513
- s.start("Validating email...");
19721
+ s.start("Checking account...");
19514
19722
  const result = await validateEmailWithTimeback(targetEnv, currentCreds.clientId, currentCreds.clientSecret, email3);
19515
19723
  if (!result.valid) {
19516
- s.stop(red("Email validation failed"));
19517
- M2.error(result.error ?? "Unknown error");
19518
- M2.info("Please contact a Timeback admin to set up your account.");
19724
+ if (result.reason !== "not_found") {
19725
+ s.stop(red("Account check failed"));
19726
+ M2.error(result.error ?? "Unknown error");
19727
+ if (!inline)
19728
+ outro.error("Account check failed");
19729
+ if (exitOnComplete)
19730
+ process.exit(1);
19731
+ return;
19732
+ }
19733
+ s.stop(red("No account found"));
19734
+ const { success: accountCreated, declined } = await createAccountFlow({
19735
+ environment: targetEnv,
19736
+ clientId: currentCreds.clientId,
19737
+ clientSecret: currentCreds.clientSecret,
19738
+ email: email3
19739
+ });
19740
+ if (!emailUnchanged) {
19741
+ await saveCredentials(targetEnv, {
19742
+ ...currentCreds,
19743
+ email: email3
19744
+ });
19745
+ M2.success(`Email saved for ${targetEnv}`);
19746
+ }
19747
+ if (!inline) {
19748
+ if (accountCreated || declined) {
19749
+ outro.success();
19750
+ } else {
19751
+ outro.info("Setup incomplete - run this command again to finish");
19752
+ }
19753
+ }
19754
+ if (exitOnComplete)
19755
+ process.exit(0);
19756
+ return;
19757
+ }
19758
+ s.stop(green("Account verified"));
19759
+ if (emailUnchanged) {
19519
19760
  if (!inline)
19520
- outro.error("Email validation failed");
19761
+ outro.info("Email unchanged");
19521
19762
  if (exitOnComplete)
19522
- process.exit(1);
19763
+ process.exit(0);
19523
19764
  return;
19524
19765
  }
19525
19766
  await saveCredentials(targetEnv, {
19526
19767
  ...currentCreds,
19527
19768
  email: email3
19528
19769
  });
19529
- s.stop(green(`Email updated for ${targetEnv}`));
19770
+ M2.success(`Email updated for ${targetEnv}`);
19530
19771
  if (!inline)
19531
19772
  outro.success();
19532
19773
  if (exitOnComplete)
@@ -19688,14 +19929,21 @@ async function promptInitialCredentials(options = {}) {
19688
19929
  outro.cancelled();
19689
19930
  process.exit(0);
19690
19931
  }
19932
+ const configuredEnvs = [];
19691
19933
  for (const env2 of environments) {
19692
- const creds = await promptForCredentials(env2);
19693
- if (creds) {
19694
- await saveCredentials(env2, creds);
19695
- M2.success(`${env2} credentials saved`);
19934
+ const result = await promptForCredentials(env2);
19935
+ if (result.status === "cancelled") {
19936
+ outro.cancelled();
19937
+ process.exit(0);
19938
+ }
19939
+ if (result.status === "error") {
19940
+ outro.error("Credential setup failed");
19941
+ process.exit(1);
19696
19942
  }
19943
+ await saveCredentials(env2, result.credentials);
19944
+ M2.success(`${env2} credentials saved`);
19945
+ configuredEnvs.push(env2);
19697
19946
  }
19698
- const configuredEnvs = environments;
19699
19947
  let selectedEnv;
19700
19948
  if (configuredEnvs.length === 1) {
19701
19949
  selectedEnv = configuredEnvs[0];
@@ -19835,7 +20083,7 @@ function printError3(error48, opts = {}) {
19835
20083
  parser.printError(error48);
19836
20084
  }
19837
20085
  // src/cli/lib/courses.ts
19838
- import { TimebackClient as TimebackClient2 } from "@timeback/core";
20086
+ import { TimebackClient as TimebackClient3 } from "@timeback/core";
19839
20087
  async function fetchCoursesByIds(client, ids) {
19840
20088
  const courses = [];
19841
20089
  for (const id of ids) {
@@ -19847,7 +20095,7 @@ async function fetchCoursesByIds(client, ids) {
19847
20095
  return courses;
19848
20096
  }
19849
20097
  async function fetchCourses(creds, env2, ids) {
19850
- const client = new TimebackClient2({
20098
+ const client = new TimebackClient3({
19851
20099
  env: env2,
19852
20100
  auth: { clientId: creds.clientId, clientSecret: creds.clientSecret }
19853
20101
  });
@@ -19869,7 +20117,7 @@ async function checkCoursesManaged(creds, env2, ids) {
19869
20117
  if (ids.length === 0) {
19870
20118
  return { allManaged: true, unmanagedCourses: [] };
19871
20119
  }
19872
- const client = new TimebackClient2({
20120
+ const client = new TimebackClient3({
19873
20121
  env: env2,
19874
20122
  auth: { clientId: creds.clientId, clientSecret: creds.clientSecret }
19875
20123
  });
@@ -19917,7 +20165,7 @@ async function handleCredentialSetup(options = {}) {
19917
20165
  };
19918
20166
  }
19919
20167
  // src/cli/lib/onboarding/import.ts
19920
- import { TimebackClient as TimebackClient3 } from "@timeback/core";
20168
+ import { TimebackClient as TimebackClient4 } from "@timeback/core";
19921
20169
  async function promptImportApp(credentials, configuredEnvs) {
19922
20170
  let env2;
19923
20171
  if (configuredEnvs.length === 1 && configuredEnvs[0]) {
@@ -19930,7 +20178,7 @@ async function promptImportApp(credentials, configuredEnvs) {
19930
20178
  env2 = selectedEnv;
19931
20179
  }
19932
20180
  const creds = credentials[env2];
19933
- const client = new TimebackClient3({
20181
+ const client = new TimebackClient4({
19934
20182
  env: env2,
19935
20183
  auth: { clientId: creds.clientId, clientSecret: creds.clientSecret }
19936
20184
  });
@@ -20058,10 +20306,11 @@ function buildUserConfigFromCourses(courses) {
20058
20306
  };
20059
20307
  }
20060
20308
  async function resolveFromCourseIds(courseIds, env2, credentials, configuredEnvs) {
20061
- const creds = await ensureCredentials({ env: env2, credentials, skipIntro: true });
20062
- if (!creds) {
20309
+ const ensureResult = await ensureCredentials({ env: env2, credentials, skipIntro: true });
20310
+ if (ensureResult.status !== "ok") {
20063
20311
  return null;
20064
20312
  }
20313
+ const creds = ensureResult.credentials;
20065
20314
  const courses = await fetchCourses(creds, env2, courseIds);
20066
20315
  if (courses.length === 0) {
20067
20316
  M2.warn("No courses found for the provided IDs.");
@@ -22359,7 +22608,8 @@ var cors = (options) => {
22359
22608
  async function handleBootstrap(c, ctx) {
22360
22609
  const { bootstrap } = c.get("services");
22361
22610
  const env2 = c.get("env");
22362
- const email3 = ctx.credentials[env2]?.email;
22611
+ const freshCredentials = await getSavedCredentials(env2);
22612
+ const email3 = freshCredentials?.email;
22363
22613
  const courseIds = ctx.userConfig.courseIds[env2];
22364
22614
  const result = await bootstrap.getBootstrap({ email: email3, courseIds });
22365
22615
  return c.json(result);
@@ -23291,11 +23541,15 @@ class StatusService {
23291
23541
  }
23292
23542
  async getStatus() {
23293
23543
  const configuredEnvironments = await getConfiguredEnvironments();
23544
+ const [stagingCreds, productionCreds] = await Promise.all([
23545
+ getSavedCredentials("staging"),
23546
+ getSavedCredentials("production")
23547
+ ]);
23294
23548
  return {
23295
23549
  config: this.ctx.userConfig,
23296
23550
  environment: this.ctx.defaultEnvironment,
23297
23551
  configuredEnvironments,
23298
- hasEmail: !!this.ctx.credentials.staging?.email || !!this.ctx.credentials.production?.email
23552
+ hasEmail: !!stagingCreds?.email || !!productionCreds?.email
23299
23553
  };
23300
23554
  }
23301
23555
  }
@@ -23440,7 +23694,6 @@ function createEnvMiddleware(ctx, manager) {
23440
23694
  }, 400);
23441
23695
  }
23442
23696
  if (!manager.has(env2)) {
23443
- log7.warn("Environment not configured", { env: env2 });
23444
23697
  const error48 = createStudioError("ENV_NOT_CONFIGURED", `Environment '${env2}' not configured`);
23445
23698
  return c.json({
23446
23699
  success: false,
@@ -23970,10 +24223,14 @@ function startServer(ctx, serverConfig, configFile) {
23970
24223
 
23971
24224
  // src/cli/commands/serve/index.ts
23972
24225
  async function launchServer(serverConfig, userConfig, credentials, env2, opts, configFile) {
23973
- const creds = await ensureCredentials({ env: env2, credentials, skipIntro: true });
23974
- if (!creds) {
24226
+ const ensureResult = await ensureCredentials({ env: env2, credentials, skipIntro: true });
24227
+ if (ensureResult.status === "cancelled") {
24228
+ process.exit(0);
24229
+ }
24230
+ if (ensureResult.status === "error") {
23975
24231
  process.exit(1);
23976
24232
  }
24233
+ const creds = ensureResult.credentials;
23977
24234
  const derivedSensors = await resolveSensors({
23978
24235
  config: userConfig,
23979
24236
  env: env2,
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/credentials/add.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEhF"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/credentials/add.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuFhF"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Account Creation
3
+ *
4
+ * Interactive CLI flow for creating a new Timeback user account
5
+ * when no matching account exists for the provided email.
6
+ */
7
+ import type { CredentialEnvironment } from '@timeback/internal-cli-infra';
8
+ /**
9
+ * Options for creating a new account.
10
+ */
11
+ interface CreateAccountOptions {
12
+ environment: CredentialEnvironment;
13
+ clientId: string;
14
+ clientSecret: string;
15
+ email: string;
16
+ }
17
+ /**
18
+ * Result of the account creation flow.
19
+ */
20
+ interface CreateAccountResult {
21
+ success: boolean;
22
+ /** User explicitly declined to create an account (vs cancelled or failed) */
23
+ declined?: boolean;
24
+ }
25
+ /**
26
+ * Interactive flow to create a new Timeback account.
27
+ *
28
+ * Called when no matching user is found for the provided email.
29
+ * Guides the user through entering their name and selecting/creating
30
+ * an organization.
31
+ *
32
+ * @param options - Account creation options
33
+ * @returns Result indicating success and the created user
34
+ */
35
+ export declare function createAccountFlow(options: CreateAccountOptions): Promise<CreateAccountResult>;
36
+ export {};
37
+ //# sourceMappingURL=create-account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-account.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/credentials/create-account.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAGzE;;GAEG;AACH,UAAU,oBAAoB;IAC7B,WAAW,EAAE,qBAAqB,CAAA;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB;AA2ND;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0CnG"}
@@ -1 +1 @@
1
- {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/credentials/email.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqH7E"}
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/credentials/email.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqJ7E"}
@@ -7,7 +7,7 @@ interface PromptInitialCredentialsOptions {
7
7
  * Runs the first-time credential setup flow.
8
8
  *
9
9
  * @param options - Options for the prompt
10
- * @returns The selected environment to use for this run, or null if cancelled
10
+ * @returns The selected environment to use for this run, or null if cancelled/error
11
11
  */
12
12
  export declare function promptInitialCredentials(options?: PromptInitialCredentialsOptions): Promise<CredentialEnvironment | null>;
13
13
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"initial.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/credentials/lib/initial.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAEzE,UAAU,+BAA+B;IACxC,kEAAkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,GAAE,+BAAoC,GAC3C,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAyDvC"}
1
+ {"version":3,"file":"initial.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/credentials/lib/initial.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAEzE,UAAU,+BAA+B;IACxC,kEAAkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,GAAE,+BAAoC,GAC3C,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAoEvC"}
@@ -42,7 +42,7 @@ export declare function buildUserConfigFromCourses(courses: CourseConfig[]): Loa
42
42
  * @param env - Target environment
43
43
  * @param credentials - Credentials map
44
44
  * @param configuredEnvs - List of configured environments
45
- * @returns Resolved config, or null if cancelled
45
+ * @returns Resolved config, or null if cancelled/error
46
46
  */
47
47
  export declare function resolveFromCourseIds(courseIds: string[], env: Environment, credentials: EnvironmentCredentials, configuredEnvs: Environment[]): Promise<ResolvedConfig | null>;
48
48
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/serve/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0BH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EACX,WAAW,EACX,WAAW,EACX,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,EACb,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3D,UAAU,yBAAyB;IAClC,QAAQ,EAAE,cAAc,CAAA;IACxB,WAAW,EAAE,sBAAsB,CAAA;IACnC,cAAc,EAAE,WAAW,EAAE,CAAA;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACxC,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,EAAE,YAAY,EAClB,kBAAkB,EAAE,WAAW,GAC7B,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAqF3C;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,CAqBhF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,gBAAgB,CAkBpF;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACzC,SAAS,EAAE,MAAM,EAAE,EACnB,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,sBAAsB,EACnC,cAAc,EAAE,WAAW,EAAE,GAC3B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA8BhC;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC9C,WAAW,EAAE,sBAAsB,EACnC,cAAc,EAAE,WAAW,EAAE,EAC7B,UAAU,EAAE,WAAW,EACvB,UAAU,GAAE,aAAkB,GAC5B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC;AAmCD;;;;;;;;;GASG;AACH;;GAEG;AACH,UAAU,qBAAqB;IAC9B,MAAM,EAAE,gBAAgB,CAAA;IACxB,GAAG,EAAE,WAAW,CAAA;IAChB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,WAAW,CAAA;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CACnC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CA2EtC;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CAClC,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,sBAAsB,EACnC,cAAc,EAAE,WAAW,EAAE,EAC7B,UAAU,EAAE,WAAW,GACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAShC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/serve/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0BH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EACX,WAAW,EACX,WAAW,EACX,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,EACb,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3D,UAAU,yBAAyB;IAClC,QAAQ,EAAE,cAAc,CAAA;IACxB,WAAW,EAAE,sBAAsB,CAAA;IACnC,cAAc,EAAE,WAAW,EAAE,CAAA;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACxC,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,EAAE,YAAY,EAClB,kBAAkB,EAAE,WAAW,GAC7B,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAqF3C;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,CAqBhF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,gBAAgB,CAkBpF;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACzC,SAAS,EAAE,MAAM,EAAE,EACnB,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,sBAAsB,EACnC,cAAc,EAAE,WAAW,EAAE,GAC3B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAgChC;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC9C,WAAW,EAAE,sBAAsB,EACnC,cAAc,EAAE,WAAW,EAAE,EAC7B,UAAU,EAAE,WAAW,EACvB,UAAU,GAAE,aAAkB,GAC5B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC;AAmCD;;;;;;;;;GASG;AACH;;GAEG;AACH,UAAU,qBAAqB;IAC9B,MAAM,EAAE,gBAAgB,CAAA;IACxB,GAAG,EAAE,WAAW,CAAA;IAChB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,WAAW,CAAA;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CACnC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CA2EtC;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CAClC,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,sBAAsB,EACnC,cAAc,EAAE,WAAW,EAAE,EAC7B,UAAU,EAAE,WAAW,GACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAShC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/serve/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAmM3C;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCzF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/serve/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AA0M3C;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCzF"}
package/dist/index.js CHANGED
@@ -840,6 +840,11 @@ ${t}
840
840
  ${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
841
841
  ${c}
842
842
  ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
843
+ `);
844
+ };
845
+ var xe = (t = "") => {
846
+ process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
847
+
843
848
  `);
844
849
  };
845
850
  var Ie = (t = "") => {
@@ -14585,7 +14590,7 @@ function intro(title) {
14585
14590
  }
14586
14591
  var outro = {
14587
14592
  success: (message = "Done") => Se(green(message)),
14588
- cancelled: () => Se(dim("Cancelled")),
14593
+ cancelled: () => xe(dim("Cancelled")),
14589
14594
  error: (message) => Se(red(message)),
14590
14595
  warn: (message) => Se(yellow(message)),
14591
14596
  info: (message) => Se(dim(message))
@@ -14685,8 +14690,8 @@ async function getConfiguredEnvironments() {
14685
14690
  return configured;
14686
14691
  }
14687
14692
  function getEnvCredentials() {
14688
- const clientId = process.env.TIMEBACK_CLIENT_ID;
14689
- const clientSecret = process.env.TIMEBACK_CLIENT_SECRET;
14693
+ const clientId = process.env.TIMEBACK_API_CLIENT_ID ?? process.env.TIMEBACK_CLIENT_ID;
14694
+ const clientSecret = process.env.TIMEBACK_API_CLIENT_SECRET ?? process.env.TIMEBACK_CLIENT_SECRET;
14690
14695
  if (clientId && clientSecret) {
14691
14696
  const result = CredentialsSchema.safeParse({ clientId, clientSecret });
14692
14697
  if (result.success) {
@@ -14730,19 +14735,23 @@ async function validateEmailWithTimeback(environment, clientId, clientSecret, em
14730
14735
  });
14731
14736
  try {
14732
14737
  const page = await client.oneroster.users.list({
14733
- where: { email: email3 },
14738
+ where: {
14739
+ email: email3,
14740
+ status: "active"
14741
+ },
14734
14742
  limit: 1
14735
14743
  });
14736
14744
  if (page.data.length === 0) {
14737
14745
  return {
14738
14746
  valid: false,
14747
+ reason: "not_found",
14739
14748
  error: `No user found with email "${email3}" in ${environment}`
14740
14749
  };
14741
14750
  }
14742
14751
  return { valid: true };
14743
14752
  } catch (error48) {
14744
14753
  const message = error48 instanceof Error ? error48.message : "Unknown error";
14745
- return { valid: false, error: `Failed to validate email: ${message}` };
14754
+ return { valid: false, reason: "api_error", error: `Failed to validate email: ${message}` };
14746
14755
  }
14747
14756
  }
14748
14757
 
@@ -14758,7 +14767,7 @@ async function promptForCredentials(environment) {
14758
14767
  }
14759
14768
  });
14760
14769
  if (isCancelled(clientId))
14761
- return null;
14770
+ return { status: "cancelled" };
14762
14771
  const clientSecret = await ge({
14763
14772
  message: `Client Secret ${dim(`(${environment})`)}`,
14764
14773
  validate: (value) => {
@@ -14768,7 +14777,7 @@ async function promptForCredentials(environment) {
14768
14777
  }
14769
14778
  });
14770
14779
  if (isCancelled(clientSecret))
14771
- return null;
14780
+ return { status: "cancelled" };
14772
14781
  const email3 = await he({
14773
14782
  message: `Your email ${dim("(for fetching your OneRoster profile)")}`,
14774
14783
  placeholder: "you@example.com",
@@ -14781,33 +14790,47 @@ async function promptForCredentials(environment) {
14781
14790
  }
14782
14791
  });
14783
14792
  if (isCancelled(email3))
14784
- return null;
14793
+ return { status: "cancelled" };
14785
14794
  if (email3) {
14786
14795
  const s = Y2();
14787
14796
  s.start("Validating email...");
14788
14797
  const result = await validateEmailWithTimeback(environment, clientId, clientSecret, email3);
14789
14798
  if (!result.valid) {
14790
- s.stop(red("Email validation failed"));
14791
- M2.error(result.error ?? "Unknown error");
14799
+ const errorMsg = result.error ?? "Email validation failed";
14800
+ s.stop(red(errorMsg));
14792
14801
  M2.info("Please contact a Timeback admin to set up your account.");
14793
- return null;
14802
+ return {
14803
+ status: "error",
14804
+ error: errorMsg
14805
+ };
14794
14806
  }
14795
14807
  s.stop(green("Email validated"));
14796
14808
  }
14797
- return { clientId, clientSecret, email: email3 || undefined };
14809
+ return {
14810
+ status: "ok",
14811
+ credentials: { clientId, clientSecret, email: email3 || undefined }
14812
+ };
14798
14813
  }
14799
14814
  async function ensureCredentials(options) {
14800
14815
  const { env: env2, credentials, introTitle = "Timeback", skipIntro = false } = options;
14801
14816
  const existing = credentials[env2];
14802
- if (existing)
14803
- return existing;
14817
+ if (existing) {
14818
+ return { status: "ok", credentials: existing, source: "existing" };
14819
+ }
14804
14820
  if (!skipIntro) {
14805
14821
  intro(introTitle);
14806
14822
  }
14807
14823
  Me(`No credentials configured for ${env2}.`, "Credential setup required");
14808
- const newCreds = await promptForCredentials(env2);
14809
- if (!newCreds)
14810
- return null;
14824
+ const promptResult = await promptForCredentials(env2);
14825
+ if (promptResult.status === "cancelled") {
14826
+ outro.cancelled();
14827
+ return { status: "cancelled" };
14828
+ }
14829
+ if (promptResult.status === "error") {
14830
+ outro.error("Credential setup failed");
14831
+ return { status: "error", error: promptResult.error };
14832
+ }
14833
+ const newCreds = promptResult.credentials;
14811
14834
  const saved = await saveCredentials(env2, newCreds);
14812
14835
  if (saved) {
14813
14836
  M2.success(`${env2} credentials saved`);
@@ -14816,7 +14839,7 @@ async function ensureCredentials(options) {
14816
14839
  M2.warn(`Credentials not saved`);
14817
14840
  }
14818
14841
  credentials[env2] = newCreds;
14819
- return newCreds;
14842
+ return { status: "ok", credentials: newCreds, source: "prompted" };
14820
14843
  }
14821
14844
  // ../internal/cli-infra/src/config/playcademy.ts
14822
14845
  var FILE_PATTERNS = ["playcademy.config.ts", "playcademy.config.js", "playcademy.config.json"];
@@ -15030,6 +15053,8 @@ var ActivityCompletedInput = exports_external.object({
15030
15053
  metricsId: exports_external.string().optional(),
15031
15054
  id: exports_external.string().optional(),
15032
15055
  extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
15056
+ edApp: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional(),
15057
+ session: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional(),
15033
15058
  attempt: exports_external.number().int().min(1).optional(),
15034
15059
  generatedExtensions: exports_external.object({
15035
15060
  pctCompleteApp: exports_external.number().optional()
@@ -15042,7 +15067,9 @@ var TimeSpentInput = exports_external.object({
15042
15067
  eventTime: IsoDateTimeString.optional(),
15043
15068
  metricsId: exports_external.string().optional(),
15044
15069
  id: exports_external.string().optional(),
15045
- extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
15070
+ extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
15071
+ edApp: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional(),
15072
+ session: exports_external.union([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]).optional()
15046
15073
  }).strict();
15047
15074
  var TimebackEvent = exports_external.union([TimebackActivityEvent, TimebackTimeSpentEvent]);
15048
15075
  var CaliperEnvelope = exports_external.object({
@@ -15232,7 +15259,7 @@ var TimebackConfig = exports_external.object({
15232
15259
  path: ["courses"]
15233
15260
  });
15234
15261
  // ../types/src/zod/edubridge.ts
15235
- var EdubridgeDateString = IsoDateTimeString;
15262
+ var EdubridgeDateString = exports_external.union([IsoDateTimeString, IsoDateString]);
15236
15263
  var EduBridgeEnrollment = exports_external.object({
15237
15264
  id: exports_external.string(),
15238
15265
  role: exports_external.string(),
@@ -17483,8 +17510,8 @@ async function addCredentials(options = {}) {
17483
17510
  }
17484
17511
  isOverwriting = true;
17485
17512
  }
17486
- const creds = await promptForCredentials(env2);
17487
- if (creds === null) {
17513
+ const result = await promptForCredentials(env2);
17514
+ if (result.status === "cancelled") {
17488
17515
  if (!inline) {
17489
17516
  if (isOverwriting) {
17490
17517
  outro.info("Existing credentials unchanged");
@@ -17492,11 +17519,21 @@ async function addCredentials(options = {}) {
17492
17519
  outro.cancelled();
17493
17520
  }
17494
17521
  }
17495
- if (exitOnComplete)
17522
+ if (exitOnComplete) {
17496
17523
  process.exit(0);
17524
+ }
17497
17525
  return;
17498
17526
  }
17499
- await saveCredentials(env2, creds);
17527
+ if (result.status === "error") {
17528
+ if (!inline) {
17529
+ outro.error("Credential setup failed");
17530
+ }
17531
+ if (exitOnComplete) {
17532
+ process.exit(1);
17533
+ }
17534
+ return;
17535
+ }
17536
+ await saveCredentials(env2, result.credentials);
17500
17537
  M2.success(`${env2} credentials saved`);
17501
17538
  savedCount++;
17502
17539
  }
@@ -17508,6 +17545,184 @@ async function addCredentials(options = {}) {
17508
17545
  if (exitOnComplete)
17509
17546
  process.exit(0);
17510
17547
  }
17548
+ // src/cli/commands/credentials/create-account.ts
17549
+ import { randomUUID } from "node:crypto";
17550
+ import { TimebackClient as TimebackClient3 } from "@timeback/core";
17551
+ async function promptName(label) {
17552
+ const value = await he({
17553
+ message: label,
17554
+ placeholder: "Enter name",
17555
+ validate: (v2) => {
17556
+ if (!v2?.trim())
17557
+ return `${label} is required`;
17558
+ }
17559
+ });
17560
+ if (isCancelled(value))
17561
+ return null;
17562
+ return value.trim();
17563
+ }
17564
+ async function searchOrganizations(client, query) {
17565
+ const allOrgs = await client.oneroster.orgs.listAll({
17566
+ where: { status: "active" },
17567
+ max: 100
17568
+ });
17569
+ if (!query.trim())
17570
+ return allOrgs;
17571
+ const lowerQuery = query.toLowerCase().trim();
17572
+ return allOrgs.filter((org) => org.name?.toLowerCase().includes(lowerQuery));
17573
+ }
17574
+ async function searchForOrganization(client) {
17575
+ const query = await he({
17576
+ message: "Search for organization",
17577
+ placeholder: "Enter organization name to search"
17578
+ });
17579
+ if (isCancelled(query))
17580
+ return null;
17581
+ const s = Y2();
17582
+ s.start("Searching organizations...");
17583
+ let results;
17584
+ try {
17585
+ results = await searchOrganizations(client, query);
17586
+ s.stop(green(`Found ${results.length} result${results.length === 1 ? "" : "s"}`));
17587
+ } catch (error48) {
17588
+ s.stop(red("Failed to search organizations"));
17589
+ M2.error(error48 instanceof Error ? error48.message : "Unknown error");
17590
+ return null;
17591
+ }
17592
+ if (results.length === 0) {
17593
+ M2.warn("No organizations found matching your search");
17594
+ return promptOrganization(client);
17595
+ }
17596
+ const validResults = results.filter((org) => org.sourcedId);
17597
+ if (validResults.length === 0) {
17598
+ M2.warn("No valid organizations found (missing IDs)");
17599
+ return promptOrganization(client);
17600
+ }
17601
+ const options = validResults.map((org) => ({
17602
+ value: org.sourcedId,
17603
+ label: org.name ?? "Unnamed Organization"
17604
+ }));
17605
+ options.push({ value: "__back__", label: `${dim("←")} Back to options` });
17606
+ const selection = await ve({
17607
+ message: "Select an organization",
17608
+ options
17609
+ });
17610
+ if (isCancelled(selection))
17611
+ return null;
17612
+ if (selection === "__back__") {
17613
+ return promptOrganization(client);
17614
+ }
17615
+ return validResults.find((org) => org.sourcedId === selection) ?? null;
17616
+ }
17617
+ async function promptOrganization(client) {
17618
+ const action = await ve({
17619
+ message: "Organization",
17620
+ options: [
17621
+ { value: "search", label: "Search for existing organization" },
17622
+ { value: "create", label: "Create new organization" }
17623
+ ]
17624
+ });
17625
+ if (isCancelled(action))
17626
+ return null;
17627
+ if (action === "create") {
17628
+ return createNewOrganization(client);
17629
+ }
17630
+ return searchForOrganization(client);
17631
+ }
17632
+ async function createNewOrganization(client) {
17633
+ const name = await he({
17634
+ message: "Organization name",
17635
+ placeholder: "Enter organization name",
17636
+ validate: (v2) => {
17637
+ if (!v2?.trim())
17638
+ return "Organization name is required";
17639
+ }
17640
+ });
17641
+ if (isCancelled(name))
17642
+ return null;
17643
+ const s = Y2();
17644
+ s.start("Creating organization...");
17645
+ const sourcedId = randomUUID();
17646
+ try {
17647
+ await client.oneroster.orgs.create({
17648
+ sourcedId,
17649
+ name: name.trim(),
17650
+ type: "school",
17651
+ status: "active"
17652
+ });
17653
+ const organization = await client.oneroster.orgs.get(sourcedId);
17654
+ s.stop(green(`Organization "${name}" created`));
17655
+ return organization;
17656
+ } catch (error48) {
17657
+ s.stop(red("Failed to create organization"));
17658
+ M2.error(error48 instanceof Error ? error48.message : "Unknown error");
17659
+ return null;
17660
+ }
17661
+ }
17662
+ async function createUser(client, email3, givenName, familyName, organizationId) {
17663
+ const s = Y2();
17664
+ s.start("Creating account...");
17665
+ const sourcedId = randomUUID();
17666
+ try {
17667
+ await client.oneroster.users.create({
17668
+ sourcedId,
17669
+ givenName,
17670
+ familyName,
17671
+ email: email3.toLowerCase(),
17672
+ enabledUser: true,
17673
+ status: "active",
17674
+ roles: [
17675
+ {
17676
+ roleType: "primary",
17677
+ role: "administrator",
17678
+ org: { sourcedId: organizationId }
17679
+ }
17680
+ ]
17681
+ });
17682
+ const user = await client.oneroster.users.get(sourcedId);
17683
+ s.stop(green("Account created successfully"));
17684
+ return user;
17685
+ } catch (error48) {
17686
+ s.stop(red("Failed to create account"));
17687
+ M2.error(error48 instanceof Error ? error48.message : "Unknown error");
17688
+ return null;
17689
+ }
17690
+ }
17691
+ async function createAccountFlow(options) {
17692
+ const { environment, clientId, clientSecret, email: email3 } = options;
17693
+ M2.info("");
17694
+ M2.info(`No account found for ${dim(email3)} in ${environment}`);
17695
+ const shouldCreate = await ye({
17696
+ message: "Would you like to create a new account?",
17697
+ initialValue: true
17698
+ });
17699
+ if (isCancelled(shouldCreate)) {
17700
+ return { success: false };
17701
+ }
17702
+ if (!shouldCreate) {
17703
+ return { success: false, declined: true };
17704
+ }
17705
+ const client = new TimebackClient3({
17706
+ env: environment,
17707
+ auth: { clientId, clientSecret }
17708
+ });
17709
+ const givenName = await promptName("First name");
17710
+ if (!givenName)
17711
+ return { success: false };
17712
+ const familyName = await promptName("Last name");
17713
+ if (!familyName)
17714
+ return { success: false };
17715
+ const organization = await promptOrganization(client);
17716
+ if (!organization?.sourcedId)
17717
+ return { success: false };
17718
+ const user = await createUser(client, email3, givenName, familyName, organization.sourcedId);
17719
+ if (!user) {
17720
+ return { success: false };
17721
+ }
17722
+ M2.success(`Account created for ${user.givenName} ${user.familyName}`);
17723
+ return { success: true };
17724
+ }
17725
+
17511
17726
  // src/cli/commands/credentials/email.ts
17512
17727
  async function updateEmail(options = {}) {
17513
17728
  const { exitOnComplete = true, inline = false } = options;
@@ -17576,32 +17791,58 @@ async function updateEmail(options = {}) {
17576
17791
  return;
17577
17792
  }
17578
17793
  const emailUnchanged = email3 === (currentEmail ?? "");
17579
- if (emailUnchanged) {
17580
- if (!inline)
17581
- outro.info("Email unchanged");
17582
- if (exitOnComplete)
17583
- process.exit(0);
17584
- return;
17585
- }
17586
17794
  if (email3) {
17587
17795
  const s = Y2();
17588
- s.start("Validating email...");
17796
+ s.start("Checking account...");
17589
17797
  const result = await validateEmailWithTimeback(targetEnv, currentCreds.clientId, currentCreds.clientSecret, email3);
17590
17798
  if (!result.valid) {
17591
- s.stop(red("Email validation failed"));
17592
- M2.error(result.error ?? "Unknown error");
17593
- M2.info("Please contact a Timeback admin to set up your account.");
17799
+ if (result.reason !== "not_found") {
17800
+ s.stop(red("Account check failed"));
17801
+ M2.error(result.error ?? "Unknown error");
17802
+ if (!inline)
17803
+ outro.error("Account check failed");
17804
+ if (exitOnComplete)
17805
+ process.exit(1);
17806
+ return;
17807
+ }
17808
+ s.stop(red("No account found"));
17809
+ const { success: accountCreated, declined } = await createAccountFlow({
17810
+ environment: targetEnv,
17811
+ clientId: currentCreds.clientId,
17812
+ clientSecret: currentCreds.clientSecret,
17813
+ email: email3
17814
+ });
17815
+ if (!emailUnchanged) {
17816
+ await saveCredentials(targetEnv, {
17817
+ ...currentCreds,
17818
+ email: email3
17819
+ });
17820
+ M2.success(`Email saved for ${targetEnv}`);
17821
+ }
17822
+ if (!inline) {
17823
+ if (accountCreated || declined) {
17824
+ outro.success();
17825
+ } else {
17826
+ outro.info("Setup incomplete - run this command again to finish");
17827
+ }
17828
+ }
17829
+ if (exitOnComplete)
17830
+ process.exit(0);
17831
+ return;
17832
+ }
17833
+ s.stop(green("Account verified"));
17834
+ if (emailUnchanged) {
17594
17835
  if (!inline)
17595
- outro.error("Email validation failed");
17836
+ outro.info("Email unchanged");
17596
17837
  if (exitOnComplete)
17597
- process.exit(1);
17838
+ process.exit(0);
17598
17839
  return;
17599
17840
  }
17600
17841
  await saveCredentials(targetEnv, {
17601
17842
  ...currentCreds,
17602
17843
  email: email3
17603
17844
  });
17604
- s.stop(green(`Email updated for ${targetEnv}`));
17845
+ M2.success(`Email updated for ${targetEnv}`);
17605
17846
  if (!inline)
17606
17847
  outro.success();
17607
17848
  if (exitOnComplete)
@@ -17763,14 +18004,21 @@ async function promptInitialCredentials(options = {}) {
17763
18004
  outro.cancelled();
17764
18005
  process.exit(0);
17765
18006
  }
18007
+ const configuredEnvs = [];
17766
18008
  for (const env2 of environments) {
17767
- const creds = await promptForCredentials(env2);
17768
- if (creds) {
17769
- await saveCredentials(env2, creds);
17770
- M2.success(`${env2} credentials saved`);
18009
+ const result = await promptForCredentials(env2);
18010
+ if (result.status === "cancelled") {
18011
+ outro.cancelled();
18012
+ process.exit(0);
17771
18013
  }
18014
+ if (result.status === "error") {
18015
+ outro.error("Credential setup failed");
18016
+ process.exit(1);
18017
+ }
18018
+ await saveCredentials(env2, result.credentials);
18019
+ M2.success(`${env2} credentials saved`);
18020
+ configuredEnvs.push(env2);
17772
18021
  }
17773
- const configuredEnvs = environments;
17774
18022
  let selectedEnv;
17775
18023
  if (configuredEnvs.length === 1) {
17776
18024
  selectedEnv = configuredEnvs[0];
@@ -17807,7 +18055,7 @@ async function handleCredentialSetup(options = {}) {
17807
18055
  };
17808
18056
  }
17809
18057
  // src/cli/lib/onboarding/import.ts
17810
- import { TimebackClient as TimebackClient3 } from "@timeback/core";
18058
+ import { TimebackClient as TimebackClient4 } from "@timeback/core";
17811
18059
  async function promptImportApp(credentials, configuredEnvs) {
17812
18060
  let env2;
17813
18061
  if (configuredEnvs.length === 1 && configuredEnvs[0]) {
@@ -17820,7 +18068,7 @@ async function promptImportApp(credentials, configuredEnvs) {
17820
18068
  env2 = selectedEnv;
17821
18069
  }
17822
18070
  const creds = credentials[env2];
17823
- const client = new TimebackClient3({
18071
+ const client = new TimebackClient4({
17824
18072
  env: env2,
17825
18073
  auth: { clientId: creds.clientId, clientSecret: creds.clientSecret }
17826
18074
  });
@@ -17948,10 +18196,11 @@ function buildUserConfigFromCourses(courses) {
17948
18196
  };
17949
18197
  }
17950
18198
  async function resolveFromCourseIds(courseIds, env2, credentials, configuredEnvs) {
17951
- const creds = await ensureCredentials({ env: env2, credentials, skipIntro: true });
17952
- if (!creds) {
18199
+ const ensureResult = await ensureCredentials({ env: env2, credentials, skipIntro: true });
18200
+ if (ensureResult.status !== "ok") {
17953
18201
  return null;
17954
18202
  }
18203
+ const creds = ensureResult.credentials;
17955
18204
  const courses = await fetchCourses(creds, env2, courseIds);
17956
18205
  if (courses.length === 0) {
17957
18206
  M2.warn("No courses found for the provided IDs.");
@@ -20249,7 +20498,8 @@ var cors = (options) => {
20249
20498
  async function handleBootstrap(c, ctx) {
20250
20499
  const { bootstrap } = c.get("services");
20251
20500
  const env2 = c.get("env");
20252
- const email3 = ctx.credentials[env2]?.email;
20501
+ const freshCredentials = await getSavedCredentials(env2);
20502
+ const email3 = freshCredentials?.email;
20253
20503
  const courseIds = ctx.userConfig.courseIds[env2];
20254
20504
  const result = await bootstrap.getBootstrap({ email: email3, courseIds });
20255
20505
  return c.json(result);
@@ -21181,11 +21431,15 @@ class StatusService {
21181
21431
  }
21182
21432
  async getStatus() {
21183
21433
  const configuredEnvironments = await getConfiguredEnvironments();
21434
+ const [stagingCreds, productionCreds] = await Promise.all([
21435
+ getSavedCredentials("staging"),
21436
+ getSavedCredentials("production")
21437
+ ]);
21184
21438
  return {
21185
21439
  config: this.ctx.userConfig,
21186
21440
  environment: this.ctx.defaultEnvironment,
21187
21441
  configuredEnvironments,
21188
- hasEmail: !!this.ctx.credentials.staging?.email || !!this.ctx.credentials.production?.email
21442
+ hasEmail: !!stagingCreds?.email || !!productionCreds?.email
21189
21443
  };
21190
21444
  }
21191
21445
  }
@@ -21330,7 +21584,6 @@ function createEnvMiddleware(ctx, manager) {
21330
21584
  }, 400);
21331
21585
  }
21332
21586
  if (!manager.has(env2)) {
21333
- log7.warn("Environment not configured", { env: env2 });
21334
21587
  const error48 = createStudioError("ENV_NOT_CONFIGURED", `Environment '${env2}' not configured`);
21335
21588
  return c.json({
21336
21589
  success: false,
@@ -21860,10 +22113,14 @@ function startServer(ctx, serverConfig, configFile) {
21860
22113
 
21861
22114
  // src/cli/commands/serve/index.ts
21862
22115
  async function launchServer(serverConfig, userConfig, credentials, env2, opts, configFile) {
21863
- const creds = await ensureCredentials({ env: env2, credentials, skipIntro: true });
21864
- if (!creds) {
22116
+ const ensureResult = await ensureCredentials({ env: env2, credentials, skipIntro: true });
22117
+ if (ensureResult.status === "cancelled") {
22118
+ process.exit(0);
22119
+ }
22120
+ if (ensureResult.status === "error") {
21865
22121
  process.exit(1);
21866
22122
  }
22123
+ const creds = ensureResult.credentials;
21867
22124
  const derivedSensors = await resolveSensors({
21868
22125
  config: userConfig,
21869
22126
  env: env2,
@@ -11,6 +11,9 @@ import type { EnvVariables } from '../lib';
11
11
  *
12
12
  * Requires env middleware to set `env` and `client` context variables.
13
13
  *
14
+ * NOTE: We read credentials fresh from disk to pick up changes made via CLI
15
+ * (e.g., email updates, account creation) without requiring a server restart.
16
+ *
14
17
  * @param c - Hono context with env variables
15
18
  * @param ctx - App context
16
19
  * @returns JSON response with user and courses
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/server/controllers/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAE1C;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC,EAAE,GAAG,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAU7F"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/server/controllers/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAE1C;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC,EAAE,GAAG,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAW7F"}
@@ -15,10 +15,13 @@ export declare class StatusService {
15
15
  private readonly ctx;
16
16
  constructor(ctx: AppContext);
17
17
  /**
18
- * Build the status payload.
19
- *
20
- * @returns Status payload object
21
- */
18
+ * Build the status payload.
19
+ *
20
+ * NOTE: We read credentials fresh from disk to pick up changes made via CLI
21
+ * (e.g., email updates, account creation) without requiring a server restart.
22
+ *
23
+ * @returns Status payload object
24
+ */
22
25
  getStatus(): Promise<StatusEventPayload>;
23
26
  }
24
27
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/server/services/status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD;;;;;GAKG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAEhC,YAAY,GAAG,EAAE,UAAU,EAE1B;IAED;;;;GAIE;IACI,SAAS,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAU7C;CACD"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/server/services/status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD;;;;;GAKG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAEhC,YAAY,GAAG,EAAE,UAAU,EAE1B;IAED;;;;;;;OAOG;IACG,SAAS,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAc7C;CACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "timeback-studio",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -27,7 +27,7 @@
27
27
  "dependencies": {
28
28
  "@clack/prompts": "^0.11.0",
29
29
  "@hono/node-server": "^1.19.7",
30
- "@timeback/core": "0.1.3",
30
+ "@timeback/core": "0.1.4",
31
31
  "c12": "^3.3.3",
32
32
  "colorette": "^2.0.20",
33
33
  "commander": "^14.0.2",