timeback-studio 0.1.4 → 0.1.6
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 +1486 -395
- package/dist/cli/commands/credentials/add.d.ts.map +1 -1
- package/dist/cli/commands/credentials/lib/initial.d.ts +9 -2
- package/dist/cli/commands/credentials/lib/initial.d.ts.map +1 -1
- package/dist/cli/commands/serve/config.d.ts +51 -7
- package/dist/cli/commands/serve/config.d.ts.map +1 -1
- package/dist/cli/commands/serve/env.d.ts +32 -0
- package/dist/cli/commands/serve/env.d.ts.map +1 -0
- package/dist/cli/commands/serve/index.d.ts +5 -3
- package/dist/cli/commands/serve/index.d.ts.map +1 -1
- package/dist/cli/commands/serve/server.d.ts.map +1 -1
- package/dist/cli/lib/courses.d.ts +32 -0
- package/dist/cli/lib/courses.d.ts.map +1 -1
- package/dist/cli/lib/credentials.d.ts +11 -24
- package/dist/cli/lib/credentials.d.ts.map +1 -1
- package/dist/cli/lib/index.d.ts +2 -2
- package/dist/cli/lib/index.d.ts.map +1 -1
- package/dist/cli/lib/types.d.ts +13 -0
- package/dist/cli/lib/types.d.ts.map +1 -0
- package/dist/config/types.d.ts +2 -8
- package/dist/config/types.d.ts.map +1 -1
- package/dist/index.js +15455 -14364
- package/dist/server/controllers/enrollment.d.ts.map +1 -1
- package/dist/server/services/bootstrap.d.ts.map +1 -1
- package/dist/server/services/enrollment.d.ts +5 -3
- package/dist/server/services/enrollment.d.ts.map +1 -1
- package/dist/server/services/types/enrollment.d.ts +6 -1
- package/dist/server/services/types/enrollment.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
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 = "") => {
|
|
@@ -3148,7 +3153,7 @@ var {
|
|
|
3148
3153
|
function isCancelled(value) {
|
|
3149
3154
|
return typeof value === "symbol";
|
|
3150
3155
|
}
|
|
3151
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
3156
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
3152
3157
|
var exports_external = {};
|
|
3153
3158
|
__export(exports_external, {
|
|
3154
3159
|
xor: () => xor,
|
|
@@ -3389,7 +3394,7 @@ __export(exports_external, {
|
|
|
3389
3394
|
$brand: () => $brand
|
|
3390
3395
|
});
|
|
3391
3396
|
|
|
3392
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
3397
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/index.js
|
|
3393
3398
|
var exports_core2 = {};
|
|
3394
3399
|
__export(exports_core2, {
|
|
3395
3400
|
version: () => version,
|
|
@@ -3667,7 +3672,7 @@ __export(exports_core2, {
|
|
|
3667
3672
|
$ZodAny: () => $ZodAny
|
|
3668
3673
|
});
|
|
3669
3674
|
|
|
3670
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
3675
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/core.js
|
|
3671
3676
|
var NEVER = Object.freeze({
|
|
3672
3677
|
status: "aborted"
|
|
3673
3678
|
});
|
|
@@ -3743,7 +3748,7 @@ function config(newConfig) {
|
|
|
3743
3748
|
Object.assign(globalConfig, newConfig);
|
|
3744
3749
|
return globalConfig;
|
|
3745
3750
|
}
|
|
3746
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
3751
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/util.js
|
|
3747
3752
|
var exports_util = {};
|
|
3748
3753
|
__export(exports_util, {
|
|
3749
3754
|
unwrapMessage: () => unwrapMessage,
|
|
@@ -4417,7 +4422,7 @@ class Class {
|
|
|
4417
4422
|
constructor(..._args) {}
|
|
4418
4423
|
}
|
|
4419
4424
|
|
|
4420
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
4425
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/errors.js
|
|
4421
4426
|
var initializer = (inst, def) => {
|
|
4422
4427
|
inst.name = "$ZodError";
|
|
4423
4428
|
Object.defineProperty(inst, "_zod", {
|
|
@@ -4554,7 +4559,7 @@ function prettifyError(error) {
|
|
|
4554
4559
|
`);
|
|
4555
4560
|
}
|
|
4556
4561
|
|
|
4557
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
4562
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/parse.js
|
|
4558
4563
|
var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
4559
4564
|
const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
|
4560
4565
|
const result = schema._zod.run({ value, issues: [] }, ctx);
|
|
@@ -4641,7 +4646,7 @@ var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
|
|
|
4641
4646
|
return _safeParseAsync(_Err)(schema, value, _ctx);
|
|
4642
4647
|
};
|
|
4643
4648
|
var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
|
|
4644
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
4649
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/regexes.js
|
|
4645
4650
|
var exports_regexes = {};
|
|
4646
4651
|
__export(exports_regexes, {
|
|
4647
4652
|
xid: () => xid,
|
|
@@ -4798,7 +4803,7 @@ var sha512_hex = /^[0-9a-fA-F]{128}$/;
|
|
|
4798
4803
|
var sha512_base64 = /* @__PURE__ */ fixedBase64(86, "==");
|
|
4799
4804
|
var sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
|
|
4800
4805
|
|
|
4801
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
4806
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/checks.js
|
|
4802
4807
|
var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
|
|
4803
4808
|
var _a;
|
|
4804
4809
|
inst._zod ?? (inst._zod = {});
|
|
@@ -5345,7 +5350,7 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
|
|
|
5345
5350
|
};
|
|
5346
5351
|
});
|
|
5347
5352
|
|
|
5348
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
5353
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/doc.js
|
|
5349
5354
|
class Doc {
|
|
5350
5355
|
constructor(args = []) {
|
|
5351
5356
|
this.content = [];
|
|
@@ -5383,14 +5388,14 @@ class Doc {
|
|
|
5383
5388
|
}
|
|
5384
5389
|
}
|
|
5385
5390
|
|
|
5386
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
5391
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/versions.js
|
|
5387
5392
|
var version = {
|
|
5388
5393
|
major: 4,
|
|
5389
5394
|
minor: 3,
|
|
5390
|
-
patch:
|
|
5395
|
+
patch: 6
|
|
5391
5396
|
};
|
|
5392
5397
|
|
|
5393
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
5398
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/schemas.js
|
|
5394
5399
|
var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
5395
5400
|
var _a;
|
|
5396
5401
|
inst ?? (inst = {});
|
|
@@ -6673,7 +6678,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
|
|
|
6673
6678
|
if (keyResult instanceof Promise) {
|
|
6674
6679
|
throw new Error("Async schemas not supported in object keys currently");
|
|
6675
6680
|
}
|
|
6676
|
-
const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length
|
|
6681
|
+
const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
|
|
6677
6682
|
if (checkNumericKey) {
|
|
6678
6683
|
const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
|
|
6679
6684
|
if (retryResult instanceof Promise) {
|
|
@@ -7352,7 +7357,7 @@ function handleRefineResult(result, payload, input, inst) {
|
|
|
7352
7357
|
payload.issues.push(issue(_iss));
|
|
7353
7358
|
}
|
|
7354
7359
|
}
|
|
7355
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
7360
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/index.js
|
|
7356
7361
|
var exports_locales = {};
|
|
7357
7362
|
__export(exports_locales, {
|
|
7358
7363
|
zhTW: () => zh_TW_default,
|
|
@@ -7406,7 +7411,7 @@ __export(exports_locales, {
|
|
|
7406
7411
|
ar: () => ar_default
|
|
7407
7412
|
});
|
|
7408
7413
|
|
|
7409
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
7414
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ar.js
|
|
7410
7415
|
var error = () => {
|
|
7411
7416
|
const Sizable = {
|
|
7412
7417
|
string: { unit: "حرف", verb: "أن يحوي" },
|
|
@@ -7512,7 +7517,7 @@ function ar_default() {
|
|
|
7512
7517
|
localeError: error()
|
|
7513
7518
|
};
|
|
7514
7519
|
}
|
|
7515
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
7520
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/az.js
|
|
7516
7521
|
var error2 = () => {
|
|
7517
7522
|
const Sizable = {
|
|
7518
7523
|
string: { unit: "simvol", verb: "olmalıdır" },
|
|
@@ -7617,7 +7622,7 @@ function az_default() {
|
|
|
7617
7622
|
localeError: error2()
|
|
7618
7623
|
};
|
|
7619
7624
|
}
|
|
7620
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
7625
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/be.js
|
|
7621
7626
|
function getBelarusianPlural(count, one, few, many) {
|
|
7622
7627
|
const absCount = Math.abs(count);
|
|
7623
7628
|
const lastDigit = absCount % 10;
|
|
@@ -7773,7 +7778,7 @@ function be_default() {
|
|
|
7773
7778
|
localeError: error3()
|
|
7774
7779
|
};
|
|
7775
7780
|
}
|
|
7776
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
7781
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/bg.js
|
|
7777
7782
|
var error4 = () => {
|
|
7778
7783
|
const Sizable = {
|
|
7779
7784
|
string: { unit: "символа", verb: "да съдържа" },
|
|
@@ -7893,7 +7898,7 @@ function bg_default() {
|
|
|
7893
7898
|
localeError: error4()
|
|
7894
7899
|
};
|
|
7895
7900
|
}
|
|
7896
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
7901
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ca.js
|
|
7897
7902
|
var error5 = () => {
|
|
7898
7903
|
const Sizable = {
|
|
7899
7904
|
string: { unit: "caràcters", verb: "contenir" },
|
|
@@ -8000,7 +8005,7 @@ function ca_default() {
|
|
|
8000
8005
|
localeError: error5()
|
|
8001
8006
|
};
|
|
8002
8007
|
}
|
|
8003
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8008
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/cs.js
|
|
8004
8009
|
var error6 = () => {
|
|
8005
8010
|
const Sizable = {
|
|
8006
8011
|
string: { unit: "znaků", verb: "mít" },
|
|
@@ -8111,7 +8116,7 @@ function cs_default() {
|
|
|
8111
8116
|
localeError: error6()
|
|
8112
8117
|
};
|
|
8113
8118
|
}
|
|
8114
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8119
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/da.js
|
|
8115
8120
|
var error7 = () => {
|
|
8116
8121
|
const Sizable = {
|
|
8117
8122
|
string: { unit: "tegn", verb: "havde" },
|
|
@@ -8226,7 +8231,7 @@ function da_default() {
|
|
|
8226
8231
|
localeError: error7()
|
|
8227
8232
|
};
|
|
8228
8233
|
}
|
|
8229
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8234
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/de.js
|
|
8230
8235
|
var error8 = () => {
|
|
8231
8236
|
const Sizable = {
|
|
8232
8237
|
string: { unit: "Zeichen", verb: "zu haben" },
|
|
@@ -8334,7 +8339,7 @@ function de_default() {
|
|
|
8334
8339
|
localeError: error8()
|
|
8335
8340
|
};
|
|
8336
8341
|
}
|
|
8337
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8342
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/en.js
|
|
8338
8343
|
var error9 = () => {
|
|
8339
8344
|
const Sizable = {
|
|
8340
8345
|
string: { unit: "characters", verb: "to have" },
|
|
@@ -8440,7 +8445,7 @@ function en_default() {
|
|
|
8440
8445
|
localeError: error9()
|
|
8441
8446
|
};
|
|
8442
8447
|
}
|
|
8443
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8448
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/eo.js
|
|
8444
8449
|
var error10 = () => {
|
|
8445
8450
|
const Sizable = {
|
|
8446
8451
|
string: { unit: "karaktrojn", verb: "havi" },
|
|
@@ -8549,7 +8554,7 @@ function eo_default() {
|
|
|
8549
8554
|
localeError: error10()
|
|
8550
8555
|
};
|
|
8551
8556
|
}
|
|
8552
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8557
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/es.js
|
|
8553
8558
|
var error11 = () => {
|
|
8554
8559
|
const Sizable = {
|
|
8555
8560
|
string: { unit: "caracteres", verb: "tener" },
|
|
@@ -8681,7 +8686,7 @@ function es_default() {
|
|
|
8681
8686
|
localeError: error11()
|
|
8682
8687
|
};
|
|
8683
8688
|
}
|
|
8684
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8689
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/fa.js
|
|
8685
8690
|
var error12 = () => {
|
|
8686
8691
|
const Sizable = {
|
|
8687
8692
|
string: { unit: "کاراکتر", verb: "داشته باشد" },
|
|
@@ -8795,7 +8800,7 @@ function fa_default() {
|
|
|
8795
8800
|
localeError: error12()
|
|
8796
8801
|
};
|
|
8797
8802
|
}
|
|
8798
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8803
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/fi.js
|
|
8799
8804
|
var error13 = () => {
|
|
8800
8805
|
const Sizable = {
|
|
8801
8806
|
string: { unit: "merkkiä", subject: "merkkijonon" },
|
|
@@ -8907,7 +8912,7 @@ function fi_default() {
|
|
|
8907
8912
|
localeError: error13()
|
|
8908
8913
|
};
|
|
8909
8914
|
}
|
|
8910
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
8915
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/fr.js
|
|
8911
8916
|
var error14 = () => {
|
|
8912
8917
|
const Sizable = {
|
|
8913
8918
|
string: { unit: "caractères", verb: "avoir" },
|
|
@@ -9015,7 +9020,7 @@ function fr_default() {
|
|
|
9015
9020
|
localeError: error14()
|
|
9016
9021
|
};
|
|
9017
9022
|
}
|
|
9018
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9023
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/fr-CA.js
|
|
9019
9024
|
var error15 = () => {
|
|
9020
9025
|
const Sizable = {
|
|
9021
9026
|
string: { unit: "caractères", verb: "avoir" },
|
|
@@ -9122,7 +9127,7 @@ function fr_CA_default() {
|
|
|
9122
9127
|
localeError: error15()
|
|
9123
9128
|
};
|
|
9124
9129
|
}
|
|
9125
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9130
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/he.js
|
|
9126
9131
|
var error16 = () => {
|
|
9127
9132
|
const TypeNames = {
|
|
9128
9133
|
string: { label: "מחרוזת", gender: "f" },
|
|
@@ -9315,7 +9320,7 @@ function he_default() {
|
|
|
9315
9320
|
localeError: error16()
|
|
9316
9321
|
};
|
|
9317
9322
|
}
|
|
9318
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9323
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/hu.js
|
|
9319
9324
|
var error17 = () => {
|
|
9320
9325
|
const Sizable = {
|
|
9321
9326
|
string: { unit: "karakter", verb: "legyen" },
|
|
@@ -9423,7 +9428,7 @@ function hu_default() {
|
|
|
9423
9428
|
localeError: error17()
|
|
9424
9429
|
};
|
|
9425
9430
|
}
|
|
9426
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9431
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/hy.js
|
|
9427
9432
|
function getArmenianPlural(count, one, many) {
|
|
9428
9433
|
return Math.abs(count) === 1 ? one : many;
|
|
9429
9434
|
}
|
|
@@ -9570,7 +9575,7 @@ function hy_default() {
|
|
|
9570
9575
|
localeError: error18()
|
|
9571
9576
|
};
|
|
9572
9577
|
}
|
|
9573
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9578
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/id.js
|
|
9574
9579
|
var error19 = () => {
|
|
9575
9580
|
const Sizable = {
|
|
9576
9581
|
string: { unit: "karakter", verb: "memiliki" },
|
|
@@ -9676,7 +9681,7 @@ function id_default() {
|
|
|
9676
9681
|
localeError: error19()
|
|
9677
9682
|
};
|
|
9678
9683
|
}
|
|
9679
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9684
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/is.js
|
|
9680
9685
|
var error20 = () => {
|
|
9681
9686
|
const Sizable = {
|
|
9682
9687
|
string: { unit: "stafi", verb: "að hafa" },
|
|
@@ -9785,7 +9790,7 @@ function is_default() {
|
|
|
9785
9790
|
localeError: error20()
|
|
9786
9791
|
};
|
|
9787
9792
|
}
|
|
9788
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9793
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/it.js
|
|
9789
9794
|
var error21 = () => {
|
|
9790
9795
|
const Sizable = {
|
|
9791
9796
|
string: { unit: "caratteri", verb: "avere" },
|
|
@@ -9893,7 +9898,7 @@ function it_default() {
|
|
|
9893
9898
|
localeError: error21()
|
|
9894
9899
|
};
|
|
9895
9900
|
}
|
|
9896
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
9901
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ja.js
|
|
9897
9902
|
var error22 = () => {
|
|
9898
9903
|
const Sizable = {
|
|
9899
9904
|
string: { unit: "文字", verb: "である" },
|
|
@@ -10000,7 +10005,7 @@ function ja_default() {
|
|
|
10000
10005
|
localeError: error22()
|
|
10001
10006
|
};
|
|
10002
10007
|
}
|
|
10003
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10008
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ka.js
|
|
10004
10009
|
var error23 = () => {
|
|
10005
10010
|
const Sizable = {
|
|
10006
10011
|
string: { unit: "სიმბოლო", verb: "უნდა შეიცავდეს" },
|
|
@@ -10112,7 +10117,7 @@ function ka_default() {
|
|
|
10112
10117
|
localeError: error23()
|
|
10113
10118
|
};
|
|
10114
10119
|
}
|
|
10115
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10120
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/km.js
|
|
10116
10121
|
var error24 = () => {
|
|
10117
10122
|
const Sizable = {
|
|
10118
10123
|
string: { unit: "តួអក្សរ", verb: "គួរមាន" },
|
|
@@ -10223,11 +10228,11 @@ function km_default() {
|
|
|
10223
10228
|
};
|
|
10224
10229
|
}
|
|
10225
10230
|
|
|
10226
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10231
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/kh.js
|
|
10227
10232
|
function kh_default() {
|
|
10228
10233
|
return km_default();
|
|
10229
10234
|
}
|
|
10230
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10235
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ko.js
|
|
10231
10236
|
var error25 = () => {
|
|
10232
10237
|
const Sizable = {
|
|
10233
10238
|
string: { unit: "문자", verb: "to have" },
|
|
@@ -10338,7 +10343,7 @@ function ko_default() {
|
|
|
10338
10343
|
localeError: error25()
|
|
10339
10344
|
};
|
|
10340
10345
|
}
|
|
10341
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10346
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/lt.js
|
|
10342
10347
|
var capitalizeFirstCharacter = (text) => {
|
|
10343
10348
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
10344
10349
|
};
|
|
@@ -10541,7 +10546,7 @@ function lt_default() {
|
|
|
10541
10546
|
localeError: error26()
|
|
10542
10547
|
};
|
|
10543
10548
|
}
|
|
10544
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10549
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/mk.js
|
|
10545
10550
|
var error27 = () => {
|
|
10546
10551
|
const Sizable = {
|
|
10547
10552
|
string: { unit: "знаци", verb: "да имаат" },
|
|
@@ -10650,7 +10655,7 @@ function mk_default() {
|
|
|
10650
10655
|
localeError: error27()
|
|
10651
10656
|
};
|
|
10652
10657
|
}
|
|
10653
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10658
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ms.js
|
|
10654
10659
|
var error28 = () => {
|
|
10655
10660
|
const Sizable = {
|
|
10656
10661
|
string: { unit: "aksara", verb: "mempunyai" },
|
|
@@ -10757,7 +10762,7 @@ function ms_default() {
|
|
|
10757
10762
|
localeError: error28()
|
|
10758
10763
|
};
|
|
10759
10764
|
}
|
|
10760
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10765
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/nl.js
|
|
10761
10766
|
var error29 = () => {
|
|
10762
10767
|
const Sizable = {
|
|
10763
10768
|
string: { unit: "tekens", verb: "heeft" },
|
|
@@ -10867,7 +10872,7 @@ function nl_default() {
|
|
|
10867
10872
|
localeError: error29()
|
|
10868
10873
|
};
|
|
10869
10874
|
}
|
|
10870
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10875
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/no.js
|
|
10871
10876
|
var error30 = () => {
|
|
10872
10877
|
const Sizable = {
|
|
10873
10878
|
string: { unit: "tegn", verb: "å ha" },
|
|
@@ -10975,7 +10980,7 @@ function no_default() {
|
|
|
10975
10980
|
localeError: error30()
|
|
10976
10981
|
};
|
|
10977
10982
|
}
|
|
10978
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
10983
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ota.js
|
|
10979
10984
|
var error31 = () => {
|
|
10980
10985
|
const Sizable = {
|
|
10981
10986
|
string: { unit: "harf", verb: "olmalıdır" },
|
|
@@ -11084,7 +11089,7 @@ function ota_default() {
|
|
|
11084
11089
|
localeError: error31()
|
|
11085
11090
|
};
|
|
11086
11091
|
}
|
|
11087
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11092
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ps.js
|
|
11088
11093
|
var error32 = () => {
|
|
11089
11094
|
const Sizable = {
|
|
11090
11095
|
string: { unit: "توکي", verb: "ولري" },
|
|
@@ -11198,7 +11203,7 @@ function ps_default() {
|
|
|
11198
11203
|
localeError: error32()
|
|
11199
11204
|
};
|
|
11200
11205
|
}
|
|
11201
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11206
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/pl.js
|
|
11202
11207
|
var error33 = () => {
|
|
11203
11208
|
const Sizable = {
|
|
11204
11209
|
string: { unit: "znaków", verb: "mieć" },
|
|
@@ -11307,7 +11312,7 @@ function pl_default() {
|
|
|
11307
11312
|
localeError: error33()
|
|
11308
11313
|
};
|
|
11309
11314
|
}
|
|
11310
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11315
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/pt.js
|
|
11311
11316
|
var error34 = () => {
|
|
11312
11317
|
const Sizable = {
|
|
11313
11318
|
string: { unit: "caracteres", verb: "ter" },
|
|
@@ -11415,7 +11420,7 @@ function pt_default() {
|
|
|
11415
11420
|
localeError: error34()
|
|
11416
11421
|
};
|
|
11417
11422
|
}
|
|
11418
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11423
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ru.js
|
|
11419
11424
|
function getRussianPlural(count, one, few, many) {
|
|
11420
11425
|
const absCount = Math.abs(count);
|
|
11421
11426
|
const lastDigit = absCount % 10;
|
|
@@ -11571,7 +11576,7 @@ function ru_default() {
|
|
|
11571
11576
|
localeError: error35()
|
|
11572
11577
|
};
|
|
11573
11578
|
}
|
|
11574
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11579
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/sl.js
|
|
11575
11580
|
var error36 = () => {
|
|
11576
11581
|
const Sizable = {
|
|
11577
11582
|
string: { unit: "znakov", verb: "imeti" },
|
|
@@ -11680,7 +11685,7 @@ function sl_default() {
|
|
|
11680
11685
|
localeError: error36()
|
|
11681
11686
|
};
|
|
11682
11687
|
}
|
|
11683
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11688
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/sv.js
|
|
11684
11689
|
var error37 = () => {
|
|
11685
11690
|
const Sizable = {
|
|
11686
11691
|
string: { unit: "tecken", verb: "att ha" },
|
|
@@ -11790,7 +11795,7 @@ function sv_default() {
|
|
|
11790
11795
|
localeError: error37()
|
|
11791
11796
|
};
|
|
11792
11797
|
}
|
|
11793
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11798
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ta.js
|
|
11794
11799
|
var error38 = () => {
|
|
11795
11800
|
const Sizable = {
|
|
11796
11801
|
string: { unit: "எழுத்துக்கள்", verb: "கொண்டிருக்க வேண்டும்" },
|
|
@@ -11900,7 +11905,7 @@ function ta_default() {
|
|
|
11900
11905
|
localeError: error38()
|
|
11901
11906
|
};
|
|
11902
11907
|
}
|
|
11903
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
11908
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/th.js
|
|
11904
11909
|
var error39 = () => {
|
|
11905
11910
|
const Sizable = {
|
|
11906
11911
|
string: { unit: "ตัวอักษร", verb: "ควรมี" },
|
|
@@ -12010,7 +12015,7 @@ function th_default() {
|
|
|
12010
12015
|
localeError: error39()
|
|
12011
12016
|
};
|
|
12012
12017
|
}
|
|
12013
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12018
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/tr.js
|
|
12014
12019
|
var error40 = () => {
|
|
12015
12020
|
const Sizable = {
|
|
12016
12021
|
string: { unit: "karakter", verb: "olmalı" },
|
|
@@ -12115,7 +12120,7 @@ function tr_default() {
|
|
|
12115
12120
|
localeError: error40()
|
|
12116
12121
|
};
|
|
12117
12122
|
}
|
|
12118
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12123
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/uk.js
|
|
12119
12124
|
var error41 = () => {
|
|
12120
12125
|
const Sizable = {
|
|
12121
12126
|
string: { unit: "символів", verb: "матиме" },
|
|
@@ -12224,11 +12229,11 @@ function uk_default() {
|
|
|
12224
12229
|
};
|
|
12225
12230
|
}
|
|
12226
12231
|
|
|
12227
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12232
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ua.js
|
|
12228
12233
|
function ua_default() {
|
|
12229
12234
|
return uk_default();
|
|
12230
12235
|
}
|
|
12231
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12236
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/ur.js
|
|
12232
12237
|
var error42 = () => {
|
|
12233
12238
|
const Sizable = {
|
|
12234
12239
|
string: { unit: "حروف", verb: "ہونا" },
|
|
@@ -12338,7 +12343,7 @@ function ur_default() {
|
|
|
12338
12343
|
localeError: error42()
|
|
12339
12344
|
};
|
|
12340
12345
|
}
|
|
12341
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12346
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/uz.js
|
|
12342
12347
|
var error43 = () => {
|
|
12343
12348
|
const Sizable = {
|
|
12344
12349
|
string: { unit: "belgi", verb: "bo‘lishi kerak" },
|
|
@@ -12447,7 +12452,7 @@ function uz_default() {
|
|
|
12447
12452
|
localeError: error43()
|
|
12448
12453
|
};
|
|
12449
12454
|
}
|
|
12450
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12455
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/vi.js
|
|
12451
12456
|
var error44 = () => {
|
|
12452
12457
|
const Sizable = {
|
|
12453
12458
|
string: { unit: "ký tự", verb: "có" },
|
|
@@ -12555,7 +12560,7 @@ function vi_default() {
|
|
|
12555
12560
|
localeError: error44()
|
|
12556
12561
|
};
|
|
12557
12562
|
}
|
|
12558
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12563
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/zh-CN.js
|
|
12559
12564
|
var error45 = () => {
|
|
12560
12565
|
const Sizable = {
|
|
12561
12566
|
string: { unit: "字符", verb: "包含" },
|
|
@@ -12664,7 +12669,7 @@ function zh_CN_default() {
|
|
|
12664
12669
|
localeError: error45()
|
|
12665
12670
|
};
|
|
12666
12671
|
}
|
|
12667
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12672
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/zh-TW.js
|
|
12668
12673
|
var error46 = () => {
|
|
12669
12674
|
const Sizable = {
|
|
12670
12675
|
string: { unit: "字元", verb: "擁有" },
|
|
@@ -12771,7 +12776,7 @@ function zh_TW_default() {
|
|
|
12771
12776
|
localeError: error46()
|
|
12772
12777
|
};
|
|
12773
12778
|
}
|
|
12774
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12779
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/yo.js
|
|
12775
12780
|
var error47 = () => {
|
|
12776
12781
|
const Sizable = {
|
|
12777
12782
|
string: { unit: "àmi", verb: "ní" },
|
|
@@ -12878,7 +12883,7 @@ function yo_default() {
|
|
|
12878
12883
|
localeError: error47()
|
|
12879
12884
|
};
|
|
12880
12885
|
}
|
|
12881
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12886
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/registries.js
|
|
12882
12887
|
var _a;
|
|
12883
12888
|
var $output = Symbol("ZodOutput");
|
|
12884
12889
|
var $input = Symbol("ZodInput");
|
|
@@ -12928,7 +12933,7 @@ function registry() {
|
|
|
12928
12933
|
}
|
|
12929
12934
|
(_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry());
|
|
12930
12935
|
var globalRegistry = globalThis.__zod_globalRegistry;
|
|
12931
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
12936
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/api.js
|
|
12932
12937
|
function _string(Class2, params) {
|
|
12933
12938
|
return new Class2({
|
|
12934
12939
|
type: "string",
|
|
@@ -13848,7 +13853,7 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
|
|
|
13848
13853
|
const inst = new Class2(def);
|
|
13849
13854
|
return inst;
|
|
13850
13855
|
}
|
|
13851
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
13856
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/to-json-schema.js
|
|
13852
13857
|
function initializeContext(params) {
|
|
13853
13858
|
let target = params?.target ?? "draft-2020-12";
|
|
13854
13859
|
if (target === "draft-4")
|
|
@@ -14044,7 +14049,7 @@ function finalize(ctx, schema) {
|
|
|
14044
14049
|
}
|
|
14045
14050
|
}
|
|
14046
14051
|
}
|
|
14047
|
-
if (refSchema.$ref) {
|
|
14052
|
+
if (refSchema.$ref && refSeen.def) {
|
|
14048
14053
|
for (const key in schema2) {
|
|
14049
14054
|
if (key === "$ref" || key === "allOf")
|
|
14050
14055
|
continue;
|
|
@@ -14193,7 +14198,7 @@ var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) =
|
|
|
14193
14198
|
extractDefs(ctx, schema);
|
|
14194
14199
|
return finalize(ctx, schema);
|
|
14195
14200
|
};
|
|
14196
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
14201
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/json-schema-processors.js
|
|
14197
14202
|
var formatMap = {
|
|
14198
14203
|
guid: "uuid",
|
|
14199
14204
|
url: "uri",
|
|
@@ -14738,7 +14743,7 @@ function toJSONSchema(input, params) {
|
|
|
14738
14743
|
extractDefs(ctx, input);
|
|
14739
14744
|
return finalize(ctx, input);
|
|
14740
14745
|
}
|
|
14741
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
14746
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/json-schema-generator.js
|
|
14742
14747
|
class JSONSchemaGenerator {
|
|
14743
14748
|
get metadataRegistry() {
|
|
14744
14749
|
return this.ctx.metadataRegistry;
|
|
@@ -14797,9 +14802,9 @@ class JSONSchemaGenerator {
|
|
|
14797
14802
|
return plainResult;
|
|
14798
14803
|
}
|
|
14799
14804
|
}
|
|
14800
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
14805
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/json-schema.js
|
|
14801
14806
|
var exports_json_schema = {};
|
|
14802
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
14807
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/schemas.js
|
|
14803
14808
|
var exports_schemas2 = {};
|
|
14804
14809
|
__export(exports_schemas2, {
|
|
14805
14810
|
xor: () => xor,
|
|
@@ -14968,7 +14973,7 @@ __export(exports_schemas2, {
|
|
|
14968
14973
|
ZodAny: () => ZodAny
|
|
14969
14974
|
});
|
|
14970
14975
|
|
|
14971
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
14976
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/checks.js
|
|
14972
14977
|
var exports_checks2 = {};
|
|
14973
14978
|
__export(exports_checks2, {
|
|
14974
14979
|
uppercase: () => _uppercase,
|
|
@@ -15002,7 +15007,7 @@ __export(exports_checks2, {
|
|
|
15002
15007
|
endsWith: () => _endsWith
|
|
15003
15008
|
});
|
|
15004
15009
|
|
|
15005
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
15010
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/iso.js
|
|
15006
15011
|
var exports_iso = {};
|
|
15007
15012
|
__export(exports_iso, {
|
|
15008
15013
|
time: () => time2,
|
|
@@ -15043,7 +15048,7 @@ function duration2(params) {
|
|
|
15043
15048
|
return _isoDuration(ZodISODuration, params);
|
|
15044
15049
|
}
|
|
15045
15050
|
|
|
15046
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
15051
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/errors.js
|
|
15047
15052
|
var initializer2 = (inst, issues) => {
|
|
15048
15053
|
$ZodError.init(inst, issues);
|
|
15049
15054
|
inst.name = "ZodError";
|
|
@@ -15078,7 +15083,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
|
|
|
15078
15083
|
Parent: Error
|
|
15079
15084
|
});
|
|
15080
15085
|
|
|
15081
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
15086
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/parse.js
|
|
15082
15087
|
var parse3 = /* @__PURE__ */ _parse(ZodRealError);
|
|
15083
15088
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
15084
15089
|
var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
@@ -15092,7 +15097,7 @@ var safeDecode2 = /* @__PURE__ */ _safeDecode(ZodRealError);
|
|
|
15092
15097
|
var safeEncodeAsync2 = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
|
|
15093
15098
|
var safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
|
|
15094
15099
|
|
|
15095
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
15100
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/schemas.js
|
|
15096
15101
|
var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
15097
15102
|
$ZodType.init(inst, def);
|
|
15098
15103
|
Object.assign(inst["~standard"], {
|
|
@@ -16168,7 +16173,7 @@ function json(params) {
|
|
|
16168
16173
|
function preprocess(fn, schema) {
|
|
16169
16174
|
return pipe(transform(fn), schema);
|
|
16170
16175
|
}
|
|
16171
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
16176
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/compat.js
|
|
16172
16177
|
var ZodIssueCode = {
|
|
16173
16178
|
invalid_type: "invalid_type",
|
|
16174
16179
|
too_big: "too_big",
|
|
@@ -16192,7 +16197,7 @@ function getErrorMap() {
|
|
|
16192
16197
|
}
|
|
16193
16198
|
var ZodFirstPartyTypeKind;
|
|
16194
16199
|
(function(ZodFirstPartyTypeKind2) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
16195
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
16200
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/from-json-schema.js
|
|
16196
16201
|
var z2 = {
|
|
16197
16202
|
...exports_schemas2,
|
|
16198
16203
|
...exports_checks2,
|
|
@@ -16653,7 +16658,7 @@ function fromJSONSchema(schema, params) {
|
|
|
16653
16658
|
};
|
|
16654
16659
|
return convertSchema(schema, ctx);
|
|
16655
16660
|
}
|
|
16656
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
16661
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/coerce.js
|
|
16657
16662
|
var exports_coerce = {};
|
|
16658
16663
|
__export(exports_coerce, {
|
|
16659
16664
|
string: () => string3,
|
|
@@ -16678,7 +16683,7 @@ function date4(params) {
|
|
|
16678
16683
|
return _coercedDate(ZodDate, params);
|
|
16679
16684
|
}
|
|
16680
16685
|
|
|
16681
|
-
// ../../node_modules/.bun/zod@4.3.
|
|
16686
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
16682
16687
|
config(en_default());
|
|
16683
16688
|
// ../internal/cli-infra/src/credentials/schema.ts
|
|
16684
16689
|
var CredentialsSchema = exports_external.object({
|
|
@@ -16688,81 +16693,19 @@ var CredentialsSchema = exports_external.object({
|
|
|
16688
16693
|
});
|
|
16689
16694
|
var ClientIdSchema = exports_external.string().min(1, "Client ID is required").regex(/^[a-z0-9]+$/, "Client ID must contain only lowercase letters and numbers").length(26, "Client ID must be exactly 26 characters");
|
|
16690
16695
|
var ClientSecretSchema = exports_external.string().min(1, "Client secret is required").regex(/^[a-z0-9]+$/, "Client secret must contain only lowercase letters and numbers").max(53, "Client secret must be less than 53 characters");
|
|
16691
|
-
// ../internal/cli-infra/src/
|
|
16692
|
-
|
|
16693
|
-
|
|
16694
|
-
|
|
16695
|
-
env: environment,
|
|
16696
|
-
auth: { clientId, clientSecret }
|
|
16697
|
-
});
|
|
16698
|
-
try {
|
|
16699
|
-
const page = await client.oneroster.users.list({
|
|
16700
|
-
where: { email: email3 },
|
|
16701
|
-
limit: 1
|
|
16702
|
-
});
|
|
16703
|
-
if (page.data.length === 0) {
|
|
16704
|
-
return {
|
|
16705
|
-
valid: false,
|
|
16706
|
-
error: `No user found with email "${email3}" in ${environment}`
|
|
16707
|
-
};
|
|
16708
|
-
}
|
|
16709
|
-
return { valid: true };
|
|
16710
|
-
} catch (error48) {
|
|
16711
|
-
const message = error48 instanceof Error ? error48.message : "Unknown error";
|
|
16712
|
-
return { valid: false, error: `Failed to validate email: ${message}` };
|
|
16713
|
-
}
|
|
16696
|
+
// ../internal/cli-infra/src/ui.ts
|
|
16697
|
+
function intro(title) {
|
|
16698
|
+
console.log("");
|
|
16699
|
+
Ie(bgCyan(black(` ${title} `)));
|
|
16714
16700
|
}
|
|
16701
|
+
var outro = {
|
|
16702
|
+
success: (message = "Done") => Se(green(message)),
|
|
16703
|
+
cancelled: () => xe(dim("Cancelled")),
|
|
16704
|
+
error: (message) => Se(red(message)),
|
|
16705
|
+
warn: (message) => Se(yellow(message)),
|
|
16706
|
+
info: (message) => Se(dim(message))
|
|
16707
|
+
};
|
|
16715
16708
|
|
|
16716
|
-
// ../internal/cli-infra/src/credentials/prompts.ts
|
|
16717
|
-
async function promptForCredentials(environment) {
|
|
16718
|
-
const clientId = await he({
|
|
16719
|
-
message: `Client ID ${dim(`(${environment})`)}`,
|
|
16720
|
-
placeholder: "tb_client_...",
|
|
16721
|
-
validate: (value) => {
|
|
16722
|
-
const result = ClientIdSchema.safeParse(value);
|
|
16723
|
-
if (!result.success)
|
|
16724
|
-
return result.error.issues[0]?.message;
|
|
16725
|
-
}
|
|
16726
|
-
});
|
|
16727
|
-
if (isCancelled(clientId))
|
|
16728
|
-
return null;
|
|
16729
|
-
const clientSecret = await ge({
|
|
16730
|
-
message: `Client Secret ${dim(`(${environment})`)}`,
|
|
16731
|
-
validate: (value) => {
|
|
16732
|
-
const result = ClientSecretSchema.safeParse(value);
|
|
16733
|
-
if (!result.success)
|
|
16734
|
-
return result.error.issues[0]?.message;
|
|
16735
|
-
}
|
|
16736
|
-
});
|
|
16737
|
-
if (isCancelled(clientSecret))
|
|
16738
|
-
return null;
|
|
16739
|
-
const email3 = await he({
|
|
16740
|
-
message: `Your email ${dim("(for fetching your OneRoster profile)")}`,
|
|
16741
|
-
placeholder: "you@example.com",
|
|
16742
|
-
validate: (value) => {
|
|
16743
|
-
if (!value)
|
|
16744
|
-
return;
|
|
16745
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
16746
|
-
if (!emailRegex.test(value))
|
|
16747
|
-
return "Please enter a valid email";
|
|
16748
|
-
}
|
|
16749
|
-
});
|
|
16750
|
-
if (isCancelled(email3))
|
|
16751
|
-
return null;
|
|
16752
|
-
if (email3) {
|
|
16753
|
-
const s = Y2();
|
|
16754
|
-
s.start("Validating email...");
|
|
16755
|
-
const result = await validateEmailWithTimeback(environment, clientId, clientSecret, email3);
|
|
16756
|
-
if (!result.valid) {
|
|
16757
|
-
s.stop(red("Email validation failed"));
|
|
16758
|
-
M2.error(result.error ?? "Unknown error");
|
|
16759
|
-
M2.info("Please contact a Timeback admin to set up your account.");
|
|
16760
|
-
return null;
|
|
16761
|
-
}
|
|
16762
|
-
s.stop(green("Email validated"));
|
|
16763
|
-
}
|
|
16764
|
-
return { clientId, clientSecret, email: email3 || undefined };
|
|
16765
|
-
}
|
|
16766
16709
|
// ../internal/cli-infra/src/credentials/store.ts
|
|
16767
16710
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
16768
16711
|
import { homedir, platform as platform2 } from "node:os";
|
|
@@ -16788,12 +16731,12 @@ async function ensureCredentialsDir() {
|
|
|
16788
16731
|
try {
|
|
16789
16732
|
const stats = await stat(CREDENTIALS_DIR);
|
|
16790
16733
|
if (!stats.isDirectory()) {
|
|
16791
|
-
console.log();
|
|
16734
|
+
console.log("");
|
|
16792
16735
|
console.log(` ${red("✖")} ${bold("Cannot save credentials")}`);
|
|
16793
|
-
console.log();
|
|
16736
|
+
console.log("");
|
|
16794
16737
|
console.log(` A file exists at ${dim(CREDENTIALS_DIR)}`);
|
|
16795
16738
|
console.log(` Please remove it or rename it to allow credential storage.`);
|
|
16796
|
-
console.log();
|
|
16739
|
+
console.log("");
|
|
16797
16740
|
return false;
|
|
16798
16741
|
}
|
|
16799
16742
|
} catch {
|
|
@@ -16812,7 +16755,13 @@ async function readCredentialsStore() {
|
|
|
16812
16755
|
async function writeCredentialsStore(store) {
|
|
16813
16756
|
if (!await ensureCredentialsDir())
|
|
16814
16757
|
return false;
|
|
16815
|
-
|
|
16758
|
+
const { staging, production } = store;
|
|
16759
|
+
const cleaned = {};
|
|
16760
|
+
if (staging)
|
|
16761
|
+
cleaned.staging = staging;
|
|
16762
|
+
if (production)
|
|
16763
|
+
cleaned.production = production;
|
|
16764
|
+
await writeFile(CREDENTIALS_FILE, JSON.stringify(cleaned, null, 2), { mode: 384 });
|
|
16816
16765
|
return true;
|
|
16817
16766
|
}
|
|
16818
16767
|
async function getSavedCredentials(environment) {
|
|
@@ -16831,15 +16780,6 @@ async function saveCredentials(environment, credentials) {
|
|
|
16831
16780
|
store[environment] = credentials;
|
|
16832
16781
|
return writeCredentialsStore(store);
|
|
16833
16782
|
}
|
|
16834
|
-
async function getDefaultEnvironment() {
|
|
16835
|
-
const store = await readCredentialsStore();
|
|
16836
|
-
return store.default ?? null;
|
|
16837
|
-
}
|
|
16838
|
-
async function saveDefaultEnvironment(environment) {
|
|
16839
|
-
const store = await readCredentialsStore();
|
|
16840
|
-
store.default = environment;
|
|
16841
|
-
return writeCredentialsStore(store);
|
|
16842
|
-
}
|
|
16843
16783
|
async function clearCredentials(environment) {
|
|
16844
16784
|
if (environment) {
|
|
16845
16785
|
const store = await readCredentialsStore();
|
|
@@ -16860,8 +16800,8 @@ async function getConfiguredEnvironments() {
|
|
|
16860
16800
|
return configured;
|
|
16861
16801
|
}
|
|
16862
16802
|
function getEnvCredentials() {
|
|
16863
|
-
const clientId = process.env.TIMEBACK_CLIENT_ID;
|
|
16864
|
-
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;
|
|
16865
16805
|
if (clientId && clientSecret) {
|
|
16866
16806
|
const result = CredentialsSchema.safeParse({ clientId, clientSecret });
|
|
16867
16807
|
if (result.success) {
|
|
@@ -16884,18 +16824,132 @@ async function loadCredentials(environment) {
|
|
|
16884
16824
|
error: `No credentials found for ${environment}`
|
|
16885
16825
|
};
|
|
16886
16826
|
}
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
16827
|
+
async function loadAllCredentials() {
|
|
16828
|
+
const configuredEnvs = await getConfiguredEnvironments();
|
|
16829
|
+
const credentials = {};
|
|
16830
|
+
for (const env2 of configuredEnvs) {
|
|
16831
|
+
const result = await loadCredentials(env2);
|
|
16832
|
+
if (result.success) {
|
|
16833
|
+
credentials[env2] = result.credentials;
|
|
16834
|
+
}
|
|
16835
|
+
}
|
|
16836
|
+
return credentials;
|
|
16837
|
+
}
|
|
16838
|
+
|
|
16839
|
+
// ../internal/cli-infra/src/credentials/validation.ts
|
|
16840
|
+
import { TimebackClient } from "@timeback/core";
|
|
16841
|
+
async function validateEmailWithTimeback(environment, clientId, clientSecret, email3) {
|
|
16842
|
+
const client = new TimebackClient({
|
|
16843
|
+
env: environment,
|
|
16844
|
+
auth: { clientId, clientSecret }
|
|
16845
|
+
});
|
|
16846
|
+
try {
|
|
16847
|
+
const page = await client.oneroster.users.list({
|
|
16848
|
+
where: {
|
|
16849
|
+
email: email3,
|
|
16850
|
+
status: "active"
|
|
16851
|
+
},
|
|
16852
|
+
limit: 1
|
|
16853
|
+
});
|
|
16854
|
+
if (page.data.length === 0) {
|
|
16855
|
+
return {
|
|
16856
|
+
valid: false,
|
|
16857
|
+
error: `No user found with email "${email3}" in ${environment}`
|
|
16858
|
+
};
|
|
16859
|
+
}
|
|
16860
|
+
return { valid: true };
|
|
16861
|
+
} catch (error48) {
|
|
16862
|
+
const message = error48 instanceof Error ? error48.message : "Unknown error";
|
|
16863
|
+
return { valid: false, error: `Failed to validate email: ${message}` };
|
|
16864
|
+
}
|
|
16865
|
+
}
|
|
16866
|
+
|
|
16867
|
+
// ../internal/cli-infra/src/credentials/prompts.ts
|
|
16868
|
+
async function promptForCredentials(environment) {
|
|
16869
|
+
const clientId = await he({
|
|
16870
|
+
message: `Client ID ${dim(`(${environment})`)}`,
|
|
16871
|
+
placeholder: "tb_client_...",
|
|
16872
|
+
validate: (value) => {
|
|
16873
|
+
const result = ClientIdSchema.safeParse(value);
|
|
16874
|
+
if (!result.success)
|
|
16875
|
+
return result.error.issues[0]?.message;
|
|
16876
|
+
}
|
|
16877
|
+
});
|
|
16878
|
+
if (isCancelled(clientId))
|
|
16879
|
+
return { status: "cancelled" };
|
|
16880
|
+
const clientSecret = await ge({
|
|
16881
|
+
message: `Client Secret ${dim(`(${environment})`)}`,
|
|
16882
|
+
validate: (value) => {
|
|
16883
|
+
const result = ClientSecretSchema.safeParse(value);
|
|
16884
|
+
if (!result.success)
|
|
16885
|
+
return result.error.issues[0]?.message;
|
|
16886
|
+
}
|
|
16887
|
+
});
|
|
16888
|
+
if (isCancelled(clientSecret))
|
|
16889
|
+
return { status: "cancelled" };
|
|
16890
|
+
const email3 = await he({
|
|
16891
|
+
message: `Your email ${dim("(for fetching your OneRoster profile)")}`,
|
|
16892
|
+
placeholder: "you@example.com",
|
|
16893
|
+
validate: (value) => {
|
|
16894
|
+
if (!value)
|
|
16895
|
+
return;
|
|
16896
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
16897
|
+
if (!emailRegex.test(value))
|
|
16898
|
+
return "Please enter a valid email";
|
|
16899
|
+
}
|
|
16900
|
+
});
|
|
16901
|
+
if (isCancelled(email3))
|
|
16902
|
+
return { status: "cancelled" };
|
|
16903
|
+
if (email3) {
|
|
16904
|
+
const s = Y2();
|
|
16905
|
+
s.start("Validating email...");
|
|
16906
|
+
const result = await validateEmailWithTimeback(environment, clientId, clientSecret, email3);
|
|
16907
|
+
if (!result.valid) {
|
|
16908
|
+
const errorMsg = result.error ?? "Email validation failed";
|
|
16909
|
+
s.stop(red(errorMsg));
|
|
16910
|
+
M2.info("Please contact a Timeback admin to set up your account.");
|
|
16911
|
+
return {
|
|
16912
|
+
status: "error",
|
|
16913
|
+
error: errorMsg
|
|
16914
|
+
};
|
|
16915
|
+
}
|
|
16916
|
+
s.stop(green("Email validated"));
|
|
16917
|
+
}
|
|
16918
|
+
return {
|
|
16919
|
+
status: "ok",
|
|
16920
|
+
credentials: { clientId, clientSecret, email: email3 || undefined }
|
|
16921
|
+
};
|
|
16922
|
+
}
|
|
16923
|
+
async function ensureCredentials(options) {
|
|
16924
|
+
const { env: env2, credentials, introTitle = "Timeback", skipIntro = false } = options;
|
|
16925
|
+
const existing = credentials[env2];
|
|
16926
|
+
if (existing) {
|
|
16927
|
+
return { status: "ok", credentials: existing, source: "existing" };
|
|
16928
|
+
}
|
|
16929
|
+
if (!skipIntro) {
|
|
16930
|
+
intro(introTitle);
|
|
16931
|
+
}
|
|
16932
|
+
Me(`No credentials configured for ${env2}.`, "Credential setup required");
|
|
16933
|
+
const promptResult = await promptForCredentials(env2);
|
|
16934
|
+
if (promptResult.status === "cancelled") {
|
|
16935
|
+
outro.cancelled();
|
|
16936
|
+
return { status: "cancelled" };
|
|
16937
|
+
}
|
|
16938
|
+
if (promptResult.status === "error") {
|
|
16939
|
+
outro.error("Credential setup failed");
|
|
16940
|
+
return { status: "error", error: promptResult.error };
|
|
16941
|
+
}
|
|
16942
|
+
const newCreds = promptResult.credentials;
|
|
16943
|
+
const saved = await saveCredentials(env2, newCreds);
|
|
16944
|
+
if (saved) {
|
|
16945
|
+
M2.success(`${env2} credentials saved`);
|
|
16946
|
+
Me(`Saved to ${dim(getCredentialsPath())}`, green("Setup complete"));
|
|
16947
|
+
} else {
|
|
16948
|
+
M2.warn(`Credentials not saved`);
|
|
16949
|
+
}
|
|
16950
|
+
credentials[env2] = newCreds;
|
|
16951
|
+
return { status: "ok", credentials: newCreds, source: "prompted" };
|
|
16891
16952
|
}
|
|
16892
|
-
var outro = {
|
|
16893
|
-
success: (message = "Done") => Se(green(message)),
|
|
16894
|
-
cancelled: () => Se(dim("Cancelled")),
|
|
16895
|
-
error: (message) => Se(red(message)),
|
|
16896
|
-
warn: (message) => Se(yellow(message)),
|
|
16897
|
-
info: (message) => Se(dim(message))
|
|
16898
|
-
};
|
|
16899
16953
|
// ../internal/cli-infra/src/config/playcademy.ts
|
|
16900
16954
|
var FILE_PATTERNS = ["playcademy.config.ts", "playcademy.config.js", "playcademy.config.json"];
|
|
16901
16955
|
function parse5() {
|
|
@@ -16905,18 +16959,18 @@ function parse5() {
|
|
|
16905
16959
|
});
|
|
16906
16960
|
}
|
|
16907
16961
|
function printError(error48) {
|
|
16908
|
-
console.log();
|
|
16962
|
+
console.log("");
|
|
16909
16963
|
console.log(` ${red("✖")} ${bold("Configuration Error")}`);
|
|
16910
|
-
console.log();
|
|
16964
|
+
console.log("");
|
|
16911
16965
|
console.log(` ${error48}`);
|
|
16912
|
-
console.log();
|
|
16966
|
+
console.log("");
|
|
16913
16967
|
console.log(` ${dim("Example playcademy.config.ts:")}`);
|
|
16914
|
-
console.log();
|
|
16968
|
+
console.log("");
|
|
16915
16969
|
console.log(` ${yellow("export default {")}`);
|
|
16916
16970
|
console.log(` ${yellow(" name: 'My Playcademy App',")}`);
|
|
16917
16971
|
console.log(` ${yellow(" // TODO: Define schema")}`);
|
|
16918
16972
|
console.log(` ${yellow("}")}`);
|
|
16919
|
-
console.log();
|
|
16973
|
+
console.log("");
|
|
16920
16974
|
}
|
|
16921
16975
|
var playcademyParser = {
|
|
16922
16976
|
name: "playcademy",
|
|
@@ -16927,8 +16981,7 @@ var playcademyParser = {
|
|
|
16927
16981
|
|
|
16928
16982
|
// ../internal/cli-infra/src/config/timeback.ts
|
|
16929
16983
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
16930
|
-
import {
|
|
16931
|
-
import { loadConfig as c12LoadConfig } from "c12";
|
|
16984
|
+
import { resolve as resolve2 } from "node:path";
|
|
16932
16985
|
// ../types/src/zod/primitives.ts
|
|
16933
16986
|
var IsoDateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
16934
16987
|
var IsoDateTimeString = exports_external.string().min(1).regex(IsoDateTimeRegex, "must be a valid ISO 8601 datetime");
|
|
@@ -17294,18 +17347,24 @@ var TimebackConfig = exports_external.object({
|
|
|
17294
17347
|
message: "Duplicate courseCode found; each must be unique",
|
|
17295
17348
|
path: ["courses"]
|
|
17296
17349
|
}).refine((config2) => {
|
|
17297
|
-
return config2.courses.every((c) =>
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
|
|
17350
|
+
return config2.courses.every((c) => {
|
|
17351
|
+
if (c.sensor !== undefined || config2.sensor !== undefined) {
|
|
17352
|
+
return true;
|
|
17353
|
+
}
|
|
17354
|
+
const launchUrls = [
|
|
17355
|
+
c.launchUrl,
|
|
17356
|
+
config2.launchUrl,
|
|
17357
|
+
c.overrides?.staging?.launchUrl,
|
|
17358
|
+
c.overrides?.production?.launchUrl
|
|
17359
|
+
].filter(Boolean);
|
|
17360
|
+
return launchUrls.length > 0;
|
|
17361
|
+
});
|
|
17303
17362
|
}, {
|
|
17304
|
-
message: "Each course must have an effective
|
|
17363
|
+
message: "Each course must have an effective sensor. Either set `sensor` explicitly (top-level or per-course), or provide a `launchUrl` so sensor can be derived from its origin.",
|
|
17305
17364
|
path: ["courses"]
|
|
17306
17365
|
});
|
|
17307
17366
|
// ../types/src/zod/edubridge.ts
|
|
17308
|
-
var EdubridgeDateString =
|
|
17367
|
+
var EdubridgeDateString = IsoDateTimeString;
|
|
17309
17368
|
var EduBridgeEnrollment = exports_external.object({
|
|
17310
17369
|
id: exports_external.string(),
|
|
17311
17370
|
role: exports_external.string(),
|
|
@@ -17369,12 +17428,9 @@ var EmailOrStudentId = exports_external.object({
|
|
|
17369
17428
|
});
|
|
17370
17429
|
var SubjectTrackInput = exports_external.object({
|
|
17371
17430
|
subject: NonEmptyString,
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
});
|
|
17376
|
-
var SubjectTrackUpsertInput = SubjectTrackInput.extend({
|
|
17377
|
-
id: NonEmptyString
|
|
17431
|
+
grade: NonEmptyString,
|
|
17432
|
+
courseId: NonEmptyString,
|
|
17433
|
+
orgSourcedId: NonEmptyString.optional()
|
|
17378
17434
|
});
|
|
17379
17435
|
var EdubridgeListEnrollmentsParams = exports_external.object({
|
|
17380
17436
|
userId: NonEmptyString
|
|
@@ -18287,28 +18343,51 @@ var QtiLessonFeedbackInput = exports_external.object({
|
|
|
18287
18343
|
lessonId: exports_external.string().min(1),
|
|
18288
18344
|
humanApproved: exports_external.boolean().optional()
|
|
18289
18345
|
}).strict();
|
|
18290
|
-
// ../internal/cli-infra/src/config/
|
|
18346
|
+
// ../internal/cli-infra/src/config/constants.ts
|
|
18291
18347
|
var CONFIG_FILENAME = "timeback.config.json";
|
|
18292
|
-
var
|
|
18348
|
+
var CONFIG_SCHEMA_URL = "https://timeback.dev/schema.json";
|
|
18349
|
+
var DEFAULT_VERSION = "0.0.0";
|
|
18350
|
+
var JSON_INDENT = 2;
|
|
18351
|
+
var TOP_LEVEL_KEY_ORDER = [
|
|
18352
|
+
"$schema",
|
|
18353
|
+
"name",
|
|
18354
|
+
"launchUrl",
|
|
18355
|
+
"sensor",
|
|
18356
|
+
"defaults",
|
|
18357
|
+
"courses"
|
|
18358
|
+
];
|
|
18359
|
+
var COURSE_KEY_ORDER = [
|
|
18360
|
+
"subject",
|
|
18361
|
+
"grade",
|
|
18362
|
+
"courseCode",
|
|
18363
|
+
"level",
|
|
18364
|
+
"sensor",
|
|
18365
|
+
"launchUrl",
|
|
18366
|
+
"ids",
|
|
18367
|
+
"metadata",
|
|
18368
|
+
"overrides"
|
|
18369
|
+
];
|
|
18370
|
+
var IDS_KEY_ORDER = ["staging", "production"];
|
|
18371
|
+
var METADATA_KEY_ORDER = [
|
|
18372
|
+
"courseType",
|
|
18373
|
+
"isSupplemental",
|
|
18374
|
+
"isCustom",
|
|
18375
|
+
"publishStatus",
|
|
18376
|
+
"contactEmail",
|
|
18377
|
+
"primaryApp",
|
|
18378
|
+
"goals",
|
|
18379
|
+
"metrics"
|
|
18380
|
+
];
|
|
18381
|
+
var DEFAULTS_KEY_ORDER = ["courseCode", "level", "metadata"];
|
|
18382
|
+
var OVERRIDES_KEY_ORDER = ["staging", "production"];
|
|
18383
|
+
var ENV_OVERRIDES_KEY_ORDER = ["level", "sensor", "launchUrl", "metadata"];
|
|
18384
|
+
|
|
18385
|
+
// ../internal/cli-infra/src/config/loader.ts
|
|
18386
|
+
import { basename, extname, relative, resolve } from "node:path";
|
|
18387
|
+
import { loadConfig as c12LoadConfig } from "c12";
|
|
18293
18388
|
function isJsonConfigPath(configPath) {
|
|
18294
18389
|
return extname(configPath).toLowerCase() === ".json";
|
|
18295
18390
|
}
|
|
18296
|
-
function deriveCourseIds(config3) {
|
|
18297
|
-
const result = { staging: [], production: [] };
|
|
18298
|
-
for (const env2 of ENVIRONMENTS) {
|
|
18299
|
-
result[env2] = config3.courses.map((course) => course.ids?.[env2]).filter((id) => !!id);
|
|
18300
|
-
}
|
|
18301
|
-
return result;
|
|
18302
|
-
}
|
|
18303
|
-
async function readPackageVersion(cwd) {
|
|
18304
|
-
try {
|
|
18305
|
-
const pkgPath = resolve(cwd, "package.json");
|
|
18306
|
-
const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
|
|
18307
|
-
return pkg.version ?? "0.0.0";
|
|
18308
|
-
} catch {
|
|
18309
|
-
return "0.0.0";
|
|
18310
|
-
}
|
|
18311
|
-
}
|
|
18312
18391
|
async function loadWithC12(cwd, configPath) {
|
|
18313
18392
|
if (configPath && !isJsonConfigPath(configPath)) {
|
|
18314
18393
|
throw new Error(`Config file must be JSON (.json): ${configPath}`);
|
|
@@ -18339,6 +18418,28 @@ async function loadWithC12(cwd, configPath) {
|
|
|
18339
18418
|
configFile: result.configFile ?? resolve(cwd, configPath ?? CONFIG_FILENAME)
|
|
18340
18419
|
};
|
|
18341
18420
|
}
|
|
18421
|
+
function getRelativeConfigPath(configPath) {
|
|
18422
|
+
return relative(process.cwd(), configPath);
|
|
18423
|
+
}
|
|
18424
|
+
|
|
18425
|
+
// ../internal/cli-infra/src/config/timeback.ts
|
|
18426
|
+
var FILE_PATTERNS2 = [CONFIG_FILENAME];
|
|
18427
|
+
function deriveCourseIds(config3) {
|
|
18428
|
+
const result = { staging: [], production: [] };
|
|
18429
|
+
for (const env2 of ENVIRONMENTS) {
|
|
18430
|
+
result[env2] = config3.courses.map((course) => course.ids?.[env2]).filter((id) => !!id);
|
|
18431
|
+
}
|
|
18432
|
+
return result;
|
|
18433
|
+
}
|
|
18434
|
+
async function readPackageVersion(cwd) {
|
|
18435
|
+
try {
|
|
18436
|
+
const pkgPath = resolve2(cwd, "package.json");
|
|
18437
|
+
const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
|
|
18438
|
+
return pkg.version ?? DEFAULT_VERSION;
|
|
18439
|
+
} catch {
|
|
18440
|
+
return DEFAULT_VERSION;
|
|
18441
|
+
}
|
|
18442
|
+
}
|
|
18342
18443
|
async function parse6() {
|
|
18343
18444
|
const cwd = process.cwd();
|
|
18344
18445
|
try {
|
|
@@ -18378,23 +18479,22 @@ ${err instanceof Error ? err.message : String(err)}`
|
|
|
18378
18479
|
}
|
|
18379
18480
|
}
|
|
18380
18481
|
function printError2(error48) {
|
|
18381
|
-
console.log();
|
|
18482
|
+
console.log("");
|
|
18382
18483
|
console.log(` ${red("✖")} ${bold("Configuration Error")}`);
|
|
18383
|
-
console.log();
|
|
18484
|
+
console.log("");
|
|
18384
18485
|
console.log(` ${error48}`);
|
|
18385
|
-
console.log();
|
|
18486
|
+
console.log("");
|
|
18386
18487
|
console.log(` ${dim("Example timeback.config.json:")}`);
|
|
18387
|
-
console.log();
|
|
18488
|
+
console.log("");
|
|
18388
18489
|
console.log(` ${yellow("{")}`);
|
|
18389
18490
|
console.log(` ${yellow(' "$schema": "https://timeback.dev/schema.json",')}`);
|
|
18390
18491
|
console.log(` ${yellow(' "name": "My Timeback App",')}`);
|
|
18391
18492
|
console.log(` ${yellow(' "launchUrl": "https://example.com/play",')}`);
|
|
18392
|
-
console.log(` ${yellow(' "sensor": "https://example.com/sensor",')}`);
|
|
18393
18493
|
console.log(` ${yellow(' "courses": [')}`);
|
|
18394
18494
|
console.log(` ${yellow(' { "subject": "Math", "grade": 3 }')}`);
|
|
18395
18495
|
console.log(` ${yellow(" ]")}`);
|
|
18396
18496
|
console.log(` ${yellow("}")}`);
|
|
18397
|
-
console.log();
|
|
18497
|
+
console.log("");
|
|
18398
18498
|
}
|
|
18399
18499
|
var timebackParser = {
|
|
18400
18500
|
name: "timeback",
|
|
@@ -18402,11 +18502,450 @@ var timebackParser = {
|
|
|
18402
18502
|
parse: parse6,
|
|
18403
18503
|
printError: printError2
|
|
18404
18504
|
};
|
|
18405
|
-
// ../internal/cli-infra/src/config/
|
|
18406
|
-
function
|
|
18407
|
-
const
|
|
18408
|
-
|
|
18409
|
-
|
|
18505
|
+
// ../internal/cli-infra/src/config/generate.ts
|
|
18506
|
+
function orderKeys(obj, keyOrder) {
|
|
18507
|
+
const result = {};
|
|
18508
|
+
const objKeys = Object.keys(obj);
|
|
18509
|
+
const source = obj;
|
|
18510
|
+
for (const key of keyOrder) {
|
|
18511
|
+
if (key in source && source[key] !== undefined) {
|
|
18512
|
+
result[key] = source[key];
|
|
18513
|
+
}
|
|
18514
|
+
}
|
|
18515
|
+
for (const key of objKeys) {
|
|
18516
|
+
if (!(key in result) && source[key] !== undefined) {
|
|
18517
|
+
result[key] = source[key];
|
|
18518
|
+
}
|
|
18519
|
+
}
|
|
18520
|
+
return result;
|
|
18521
|
+
}
|
|
18522
|
+
function filterUndefined(obj) {
|
|
18523
|
+
const result = {};
|
|
18524
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
18525
|
+
if (value !== undefined) {
|
|
18526
|
+
result[key] = value;
|
|
18527
|
+
}
|
|
18528
|
+
}
|
|
18529
|
+
return result;
|
|
18530
|
+
}
|
|
18531
|
+
function formatCourseIds(ids) {
|
|
18532
|
+
if (!ids)
|
|
18533
|
+
return;
|
|
18534
|
+
const filtered = filterUndefined(ids);
|
|
18535
|
+
if (Object.keys(filtered).length === 0)
|
|
18536
|
+
return;
|
|
18537
|
+
return orderKeys(filtered, IDS_KEY_ORDER);
|
|
18538
|
+
}
|
|
18539
|
+
function formatMetadata(metadata) {
|
|
18540
|
+
if (!metadata)
|
|
18541
|
+
return;
|
|
18542
|
+
const filtered = filterUndefined(metadata);
|
|
18543
|
+
if (Object.keys(filtered).length === 0)
|
|
18544
|
+
return;
|
|
18545
|
+
return orderKeys(filtered, METADATA_KEY_ORDER);
|
|
18546
|
+
}
|
|
18547
|
+
function formatDefaults(defaults) {
|
|
18548
|
+
if (!defaults)
|
|
18549
|
+
return;
|
|
18550
|
+
const result = {};
|
|
18551
|
+
if (defaults.courseCode)
|
|
18552
|
+
result.courseCode = defaults.courseCode;
|
|
18553
|
+
if (defaults.level)
|
|
18554
|
+
result.level = defaults.level;
|
|
18555
|
+
if (defaults.metadata) {
|
|
18556
|
+
const meta3 = formatMetadata(defaults.metadata);
|
|
18557
|
+
if (meta3)
|
|
18558
|
+
result.metadata = meta3;
|
|
18559
|
+
}
|
|
18560
|
+
if (Object.keys(result).length === 0)
|
|
18561
|
+
return;
|
|
18562
|
+
return orderKeys(result, DEFAULTS_KEY_ORDER);
|
|
18563
|
+
}
|
|
18564
|
+
function formatEnvOverrides(overrides) {
|
|
18565
|
+
if (!overrides)
|
|
18566
|
+
return;
|
|
18567
|
+
const result = {};
|
|
18568
|
+
if (overrides.level)
|
|
18569
|
+
result.level = overrides.level;
|
|
18570
|
+
if (overrides.sensor)
|
|
18571
|
+
result.sensor = overrides.sensor;
|
|
18572
|
+
if (overrides.launchUrl)
|
|
18573
|
+
result.launchUrl = overrides.launchUrl;
|
|
18574
|
+
if (overrides.metadata) {
|
|
18575
|
+
const meta3 = formatMetadata(overrides.metadata);
|
|
18576
|
+
if (meta3)
|
|
18577
|
+
result.metadata = meta3;
|
|
18578
|
+
}
|
|
18579
|
+
if (Object.keys(result).length === 0)
|
|
18580
|
+
return;
|
|
18581
|
+
return orderKeys(result, ENV_OVERRIDES_KEY_ORDER);
|
|
18582
|
+
}
|
|
18583
|
+
function formatOverrides(overrides) {
|
|
18584
|
+
if (!overrides) {
|
|
18585
|
+
return;
|
|
18586
|
+
}
|
|
18587
|
+
const result = {};
|
|
18588
|
+
if (overrides.staging) {
|
|
18589
|
+
const staging = formatEnvOverrides(overrides.staging);
|
|
18590
|
+
if (staging)
|
|
18591
|
+
result.staging = staging;
|
|
18592
|
+
}
|
|
18593
|
+
if (overrides.production) {
|
|
18594
|
+
const production = formatEnvOverrides(overrides.production);
|
|
18595
|
+
if (production)
|
|
18596
|
+
result.production = production;
|
|
18597
|
+
}
|
|
18598
|
+
if (Object.keys(result).length === 0) {
|
|
18599
|
+
return;
|
|
18600
|
+
}
|
|
18601
|
+
return orderKeys(result, OVERRIDES_KEY_ORDER);
|
|
18602
|
+
}
|
|
18603
|
+
function formatCourse(course) {
|
|
18604
|
+
const result = {
|
|
18605
|
+
subject: course.subject
|
|
18606
|
+
};
|
|
18607
|
+
if (course.grade !== undefined) {
|
|
18608
|
+
result.grade = course.grade;
|
|
18609
|
+
}
|
|
18610
|
+
if (course.courseCode) {
|
|
18611
|
+
result.courseCode = course.courseCode;
|
|
18612
|
+
}
|
|
18613
|
+
if (course.level) {
|
|
18614
|
+
result.level = course.level;
|
|
18615
|
+
}
|
|
18616
|
+
if (course.sensor) {
|
|
18617
|
+
result.sensor = course.sensor;
|
|
18618
|
+
}
|
|
18619
|
+
if (course.launchUrl) {
|
|
18620
|
+
result.launchUrl = course.launchUrl;
|
|
18621
|
+
}
|
|
18622
|
+
const ids = formatCourseIds(course.ids);
|
|
18623
|
+
if (ids) {
|
|
18624
|
+
result.ids = ids;
|
|
18625
|
+
}
|
|
18626
|
+
const metadata = formatMetadata(course.metadata);
|
|
18627
|
+
if (metadata) {
|
|
18628
|
+
result.metadata = metadata;
|
|
18629
|
+
}
|
|
18630
|
+
const overrides = formatOverrides(course.overrides);
|
|
18631
|
+
if (overrides) {
|
|
18632
|
+
result.overrides = overrides;
|
|
18633
|
+
}
|
|
18634
|
+
return orderKeys(result, COURSE_KEY_ORDER);
|
|
18635
|
+
}
|
|
18636
|
+
function generateConfigContent(config3) {
|
|
18637
|
+
const output = {
|
|
18638
|
+
$schema: CONFIG_SCHEMA_URL,
|
|
18639
|
+
name: config3.name
|
|
18640
|
+
};
|
|
18641
|
+
if (config3.launchUrl) {
|
|
18642
|
+
output.launchUrl = config3.launchUrl;
|
|
18643
|
+
}
|
|
18644
|
+
if (config3.sensor) {
|
|
18645
|
+
output.sensor = config3.sensor;
|
|
18646
|
+
}
|
|
18647
|
+
const defaults = formatDefaults(config3.defaults);
|
|
18648
|
+
if (defaults) {
|
|
18649
|
+
output.defaults = defaults;
|
|
18650
|
+
}
|
|
18651
|
+
output.courses = config3.courses.map(formatCourse);
|
|
18652
|
+
const ordered = orderKeys(output, TOP_LEVEL_KEY_ORDER);
|
|
18653
|
+
return JSON.stringify(ordered, null, JSON_INDENT) + `
|
|
18654
|
+
`;
|
|
18655
|
+
}
|
|
18656
|
+
// ../internal/utils/src/server/spinner.ts
|
|
18657
|
+
import { stdout as stdout2 } from "node:process";
|
|
18658
|
+
|
|
18659
|
+
// ../internal/utils/src/server/terminal.ts
|
|
18660
|
+
import { stdout } from "node:process";
|
|
18661
|
+
var isInteractive = stdout.isTTY ?? false;
|
|
18662
|
+
var cursor = {
|
|
18663
|
+
hide: "\x1B[?25l",
|
|
18664
|
+
show: "\x1B[?25h",
|
|
18665
|
+
up: (n) => `\x1B[${n}A`,
|
|
18666
|
+
down: (n) => `\x1B[${n}B`,
|
|
18667
|
+
forward: (n) => `\x1B[${n}C`,
|
|
18668
|
+
back: (n) => `\x1B[${n}D`,
|
|
18669
|
+
clearLine: "\x1B[K",
|
|
18670
|
+
clearScreen: "\x1B[2J",
|
|
18671
|
+
home: "\x1B[H"
|
|
18672
|
+
};
|
|
18673
|
+
function stripAnsi(str) {
|
|
18674
|
+
return str.replaceAll(/\u001B\[[0-9;]*[a-zA-Z]/g, "");
|
|
18675
|
+
}
|
|
18676
|
+
|
|
18677
|
+
// ../internal/utils/src/server/spinner.ts
|
|
18678
|
+
var SPINNER_FRAMES = [
|
|
18679
|
+
10251,
|
|
18680
|
+
10265,
|
|
18681
|
+
10297,
|
|
18682
|
+
10296,
|
|
18683
|
+
10300,
|
|
18684
|
+
10292,
|
|
18685
|
+
10278,
|
|
18686
|
+
10279,
|
|
18687
|
+
10247,
|
|
18688
|
+
10255
|
|
18689
|
+
].map((code) => String.fromCodePoint(code));
|
|
18690
|
+
var SPINNER_INTERVAL = 80;
|
|
18691
|
+
var CHECK_MARK = "✔";
|
|
18692
|
+
var CROSS_MARK = "✖";
|
|
18693
|
+
var STATUS_LABELS = {
|
|
18694
|
+
pending: "[PENDING]",
|
|
18695
|
+
running: "[RUNNING]",
|
|
18696
|
+
success: "[SUCCESS]",
|
|
18697
|
+
error: "[ERROR]"
|
|
18698
|
+
};
|
|
18699
|
+
|
|
18700
|
+
class Spinner {
|
|
18701
|
+
tasks = new Map;
|
|
18702
|
+
frameIndex = 0;
|
|
18703
|
+
intervalId = null;
|
|
18704
|
+
previousLineCount = 0;
|
|
18705
|
+
printedTasks = new Set;
|
|
18706
|
+
constructor(taskIds, texts) {
|
|
18707
|
+
for (const [index, id] of taskIds.entries()) {
|
|
18708
|
+
this.tasks.set(id, {
|
|
18709
|
+
text: texts[index] ?? "",
|
|
18710
|
+
status: "pending"
|
|
18711
|
+
});
|
|
18712
|
+
}
|
|
18713
|
+
}
|
|
18714
|
+
start() {
|
|
18715
|
+
if (!isInteractive)
|
|
18716
|
+
return;
|
|
18717
|
+
stdout2.write(cursor.hide);
|
|
18718
|
+
this.render();
|
|
18719
|
+
this.intervalId = setInterval(() => {
|
|
18720
|
+
this.frameIndex = (this.frameIndex + 1) % SPINNER_FRAMES.length;
|
|
18721
|
+
this.render();
|
|
18722
|
+
}, SPINNER_INTERVAL);
|
|
18723
|
+
}
|
|
18724
|
+
updateTask(taskId, status, finalText) {
|
|
18725
|
+
const task = this.tasks.get(taskId);
|
|
18726
|
+
if (!task)
|
|
18727
|
+
return;
|
|
18728
|
+
task.status = status;
|
|
18729
|
+
if (finalText)
|
|
18730
|
+
task.finalText = finalText;
|
|
18731
|
+
if (!isInteractive) {
|
|
18732
|
+
this.renderNonInteractive(taskId, task);
|
|
18733
|
+
}
|
|
18734
|
+
}
|
|
18735
|
+
stop() {
|
|
18736
|
+
if (this.intervalId) {
|
|
18737
|
+
clearInterval(this.intervalId);
|
|
18738
|
+
this.intervalId = null;
|
|
18739
|
+
}
|
|
18740
|
+
if (isInteractive) {
|
|
18741
|
+
this.render();
|
|
18742
|
+
stdout2.write(cursor.show);
|
|
18743
|
+
}
|
|
18744
|
+
}
|
|
18745
|
+
clear() {
|
|
18746
|
+
if (this.intervalId) {
|
|
18747
|
+
clearInterval(this.intervalId);
|
|
18748
|
+
this.intervalId = null;
|
|
18749
|
+
}
|
|
18750
|
+
if (isInteractive && this.previousLineCount > 0) {
|
|
18751
|
+
stdout2.write(cursor.up(this.previousLineCount));
|
|
18752
|
+
for (let i = 0;i < this.previousLineCount; i++) {
|
|
18753
|
+
stdout2.write(`\r${cursor.clearLine}
|
|
18754
|
+
`);
|
|
18755
|
+
}
|
|
18756
|
+
stdout2.write(cursor.up(this.previousLineCount));
|
|
18757
|
+
stdout2.write(cursor.show);
|
|
18758
|
+
}
|
|
18759
|
+
this.previousLineCount = 0;
|
|
18760
|
+
}
|
|
18761
|
+
render() {
|
|
18762
|
+
if (this.previousLineCount > 0) {
|
|
18763
|
+
stdout2.write(cursor.up(this.previousLineCount));
|
|
18764
|
+
}
|
|
18765
|
+
const spinner = SPINNER_FRAMES[this.frameIndex];
|
|
18766
|
+
const visibleTasks = [...this.tasks.values()].filter((t) => t.status !== "pending");
|
|
18767
|
+
for (const task of visibleTasks) {
|
|
18768
|
+
stdout2.write(`\r${cursor.clearLine}`);
|
|
18769
|
+
console.log(this.formatLine(task, spinner));
|
|
18770
|
+
}
|
|
18771
|
+
this.previousLineCount = visibleTasks.length;
|
|
18772
|
+
}
|
|
18773
|
+
formatLine(task, spinner) {
|
|
18774
|
+
switch (task.status) {
|
|
18775
|
+
case "running":
|
|
18776
|
+
return `${blue(spinner ?? "○")} ${task.text}`;
|
|
18777
|
+
case "success":
|
|
18778
|
+
return `${green(CHECK_MARK)} ${task.finalText ?? task.text}`;
|
|
18779
|
+
case "error":
|
|
18780
|
+
return `${red(CROSS_MARK)} Failed: ${task.text}`;
|
|
18781
|
+
default:
|
|
18782
|
+
return task.text;
|
|
18783
|
+
}
|
|
18784
|
+
}
|
|
18785
|
+
renderNonInteractive(taskId, task) {
|
|
18786
|
+
const key = `${taskId}-${task.status}`;
|
|
18787
|
+
if (this.printedTasks.has(key))
|
|
18788
|
+
return;
|
|
18789
|
+
this.printedTasks.add(key);
|
|
18790
|
+
const text = task.status === "success" ? task.finalText ?? task.text : task.text;
|
|
18791
|
+
console.log(`${STATUS_LABELS[task.status]} ${stripAnsi(text)}`);
|
|
18792
|
+
}
|
|
18793
|
+
}
|
|
18794
|
+
// ../internal/utils/src/server/runtime.ts
|
|
18795
|
+
import { join as join2 } from "node:path";
|
|
18796
|
+
var STANDALONE_PATHS = [
|
|
18797
|
+
join2(".timeback", "bin"),
|
|
18798
|
+
join2(".local", "bin"),
|
|
18799
|
+
"/usr/local/bin/timeback",
|
|
18800
|
+
"/opt/homebrew/bin/timeback"
|
|
18801
|
+
];
|
|
18802
|
+
// ../internal/utils/src/server/project.ts
|
|
18803
|
+
import { existsSync } from "node:fs";
|
|
18804
|
+
import { resolve as resolve3 } from "node:path";
|
|
18805
|
+
function detectPackageManager(cwd) {
|
|
18806
|
+
const candidates = [
|
|
18807
|
+
{ pm: "bun", file: "bun.lockb" },
|
|
18808
|
+
{ pm: "bun", file: "bun.lock" },
|
|
18809
|
+
{ pm: "pnpm", file: "pnpm-lock.yaml" },
|
|
18810
|
+
{ pm: "yarn", file: "yarn.lock" },
|
|
18811
|
+
{ pm: "npm", file: "package-lock.json" }
|
|
18812
|
+
];
|
|
18813
|
+
for (const { pm, file: file2 } of candidates) {
|
|
18814
|
+
if (existsSync(resolve3(cwd, file2))) {
|
|
18815
|
+
return { packageManager: pm, reason: "lockfile", lockfile: file2 };
|
|
18816
|
+
}
|
|
18817
|
+
}
|
|
18818
|
+
return { packageManager: "npm", reason: "default" };
|
|
18819
|
+
}
|
|
18820
|
+
function getDlxCommand(pm, tool) {
|
|
18821
|
+
switch (pm) {
|
|
18822
|
+
case "bun":
|
|
18823
|
+
return { cmd: "bunx", args: [tool] };
|
|
18824
|
+
case "pnpm":
|
|
18825
|
+
return { cmd: "pnpm", args: ["dlx", tool] };
|
|
18826
|
+
case "yarn":
|
|
18827
|
+
return { cmd: "yarn", args: ["dlx", tool] };
|
|
18828
|
+
case "npm":
|
|
18829
|
+
default:
|
|
18830
|
+
return { cmd: "npx", args: ["--yes", tool] };
|
|
18831
|
+
}
|
|
18832
|
+
}
|
|
18833
|
+
// ../internal/utils/src/server/prettier.ts
|
|
18834
|
+
import { spawn } from "node:child_process";
|
|
18835
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
18836
|
+
import { resolve as resolve4 } from "node:path";
|
|
18837
|
+
function run(cmd, args, cwd, silent = false) {
|
|
18838
|
+
return new Promise((resolvePromise) => {
|
|
18839
|
+
const child = spawn(cmd, args, {
|
|
18840
|
+
cwd,
|
|
18841
|
+
stdio: silent ? "ignore" : "inherit",
|
|
18842
|
+
shell: process.platform === "win32"
|
|
18843
|
+
});
|
|
18844
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
18845
|
+
child.on("error", () => resolvePromise(1));
|
|
18846
|
+
});
|
|
18847
|
+
}
|
|
18848
|
+
function getPrettierBin(cwd) {
|
|
18849
|
+
return resolve4(cwd, "node_modules", ".bin", process.platform === "win32" ? "prettier.cmd" : "prettier");
|
|
18850
|
+
}
|
|
18851
|
+
function runPrettierUsingRunner(cwd, args) {
|
|
18852
|
+
const { packageManager } = detectPackageManager(cwd);
|
|
18853
|
+
const dlx = getDlxCommand(packageManager, "prettier");
|
|
18854
|
+
return run(dlx.cmd, [...dlx.args, ...args], cwd, true);
|
|
18855
|
+
}
|
|
18856
|
+
async function formatWithPrettier(options) {
|
|
18857
|
+
const { cwd, filePath, silent = false, label = "file" } = options;
|
|
18858
|
+
const prettierBin = getPrettierBin(cwd);
|
|
18859
|
+
const args = ["--write", filePath];
|
|
18860
|
+
const s = silent ? null : Y2();
|
|
18861
|
+
s?.start(`Formatting ${label}...`);
|
|
18862
|
+
try {
|
|
18863
|
+
let code;
|
|
18864
|
+
if (existsSync2(prettierBin)) {
|
|
18865
|
+
code = await run(prettierBin, args, cwd, true);
|
|
18866
|
+
} else {
|
|
18867
|
+
code = await runPrettierUsingRunner(cwd, args);
|
|
18868
|
+
}
|
|
18869
|
+
if (code === 0) {
|
|
18870
|
+
s?.stop(`Formatted ${label}`);
|
|
18871
|
+
return true;
|
|
18872
|
+
}
|
|
18873
|
+
s?.stop();
|
|
18874
|
+
if (!silent) {
|
|
18875
|
+
M2.warn(`Failed to format ${label}`);
|
|
18876
|
+
}
|
|
18877
|
+
return false;
|
|
18878
|
+
} catch {
|
|
18879
|
+
s?.stop();
|
|
18880
|
+
if (!silent) {
|
|
18881
|
+
M2.warn(`Failed to format ${label}`);
|
|
18882
|
+
}
|
|
18883
|
+
return false;
|
|
18884
|
+
}
|
|
18885
|
+
}
|
|
18886
|
+
// ../internal/cli-infra/src/config/update.ts
|
|
18887
|
+
import { readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
18888
|
+
async function updateTimebackConfigFile(configPath, updates, options = {}) {
|
|
18889
|
+
const { format = false, cwd = process.cwd(), silent = true } = options;
|
|
18890
|
+
try {
|
|
18891
|
+
const raw = await readFile3(configPath, "utf8");
|
|
18892
|
+
const parsed = JSON.parse(raw);
|
|
18893
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
18894
|
+
return { success: false, error: "Config file is not a JSON object." };
|
|
18895
|
+
}
|
|
18896
|
+
const { $schema: _schema, ...withoutSchema } = parsed;
|
|
18897
|
+
const current = TimebackConfig.safeParse(withoutSchema);
|
|
18898
|
+
if (!current.success) {
|
|
18899
|
+
return { success: false, error: "Config file is invalid; cannot update." };
|
|
18900
|
+
}
|
|
18901
|
+
const next = {
|
|
18902
|
+
...current.data,
|
|
18903
|
+
...Object.fromEntries(Object.entries(updates).filter(([, v2]) => v2 !== undefined))
|
|
18904
|
+
};
|
|
18905
|
+
const validated = TimebackConfig.safeParse(next);
|
|
18906
|
+
if (!validated.success) {
|
|
18907
|
+
return { success: false, error: "Update would make config invalid; refusing to write." };
|
|
18908
|
+
}
|
|
18909
|
+
await writeFile2(configPath, generateConfigContent(validated.data), "utf8");
|
|
18910
|
+
if (format) {
|
|
18911
|
+
await formatWithPrettier({ cwd, filePath: configPath, silent });
|
|
18912
|
+
}
|
|
18913
|
+
return { success: true, config: validated.data };
|
|
18914
|
+
} catch (err) {
|
|
18915
|
+
return {
|
|
18916
|
+
success: false,
|
|
18917
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
18918
|
+
};
|
|
18919
|
+
}
|
|
18920
|
+
}
|
|
18921
|
+
// ../internal/utils/src/shared/format.ts
|
|
18922
|
+
function pluralize(count, singular, plural) {
|
|
18923
|
+
return count === 1 ? singular : plural ?? `${singular}s`;
|
|
18924
|
+
}
|
|
18925
|
+
// ../internal/utils/src/shared/batching.ts
|
|
18926
|
+
var DEFAULT_BATCH_SIZE = 50;
|
|
18927
|
+
function splitIntoBatches(items, options) {
|
|
18928
|
+
const batchSize = options?.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
18929
|
+
if (batchSize <= 0)
|
|
18930
|
+
return [items.slice()];
|
|
18931
|
+
const batches = [];
|
|
18932
|
+
for (let i = 0;i < items.length; i += batchSize) {
|
|
18933
|
+
batches.push(items.slice(i, i + batchSize));
|
|
18934
|
+
}
|
|
18935
|
+
return batches;
|
|
18936
|
+
}
|
|
18937
|
+
// ../internal/utils/src/shared/promise.ts
|
|
18938
|
+
function extractFulfilled(results) {
|
|
18939
|
+
return results.filter((r2) => r2.status === "fulfilled").flatMap((r2) => r2.value);
|
|
18940
|
+
}
|
|
18941
|
+
function extractRejected(results) {
|
|
18942
|
+
return results.filter((r2) => r2.status === "rejected");
|
|
18943
|
+
}
|
|
18944
|
+
// ../internal/cli-infra/src/config/courses.ts
|
|
18945
|
+
function toCourseConfig(course, env2) {
|
|
18946
|
+
const config3 = {
|
|
18947
|
+
subject: course.subjects?.[0] ?? "None",
|
|
18948
|
+
grade: course.grades?.[0] ?? 0,
|
|
18410
18949
|
ids: {
|
|
18411
18950
|
[env2]: course.sourcedId
|
|
18412
18951
|
}
|
|
@@ -18441,12 +18980,135 @@ function toCourseConfig(course, env2) {
|
|
|
18441
18980
|
}
|
|
18442
18981
|
return config3;
|
|
18443
18982
|
}
|
|
18983
|
+
async function inferLaunchUrl(client, courseId) {
|
|
18984
|
+
try {
|
|
18985
|
+
const scopedCourse = client.oneroster.courses(courseId);
|
|
18986
|
+
const components = await scopedCourse.components({ where: { status: "active" } });
|
|
18987
|
+
const componentResourceIds = [];
|
|
18988
|
+
for (const component of components) {
|
|
18989
|
+
if (!component.sourcedId)
|
|
18990
|
+
continue;
|
|
18991
|
+
const crs = await client.oneroster.courses.componentResources({
|
|
18992
|
+
where: { "courseComponent.sourcedId": component.sourcedId, status: "active" }
|
|
18993
|
+
});
|
|
18994
|
+
for (const cr of crs) {
|
|
18995
|
+
if (cr.resource?.sourcedId) {
|
|
18996
|
+
componentResourceIds.push(cr.resource.sourcedId);
|
|
18997
|
+
}
|
|
18998
|
+
}
|
|
18999
|
+
}
|
|
19000
|
+
if (componentResourceIds.length === 0) {
|
|
19001
|
+
return;
|
|
19002
|
+
}
|
|
19003
|
+
const resourceIds = [...new Set(componentResourceIds)];
|
|
19004
|
+
const batches = splitIntoBatches(resourceIds);
|
|
19005
|
+
const batchResults = await Promise.allSettled(batches.map((batch) => client.oneroster.resources.listAll({
|
|
19006
|
+
where: { sourcedId: { in: batch } }
|
|
19007
|
+
})));
|
|
19008
|
+
const hasFailures = batchResults.some((r2) => r2.status === "rejected");
|
|
19009
|
+
if (hasFailures) {
|
|
19010
|
+
return;
|
|
19011
|
+
}
|
|
19012
|
+
const resources = extractFulfilled(batchResults);
|
|
19013
|
+
const launchUrls = new Set;
|
|
19014
|
+
for (const resource of resources) {
|
|
19015
|
+
const metadata = resource.metadata;
|
|
19016
|
+
const launchUrl = metadata?.launchUrl;
|
|
19017
|
+
if (typeof launchUrl === "string" && launchUrl.length > 0) {
|
|
19018
|
+
launchUrls.add(launchUrl);
|
|
19019
|
+
}
|
|
19020
|
+
}
|
|
19021
|
+
if (launchUrls.size === 1) {
|
|
19022
|
+
return [...launchUrls][0];
|
|
19023
|
+
}
|
|
19024
|
+
return;
|
|
19025
|
+
} catch {
|
|
19026
|
+
return;
|
|
19027
|
+
}
|
|
19028
|
+
}
|
|
18444
19029
|
|
|
18445
19030
|
// ../internal/cli-infra/src/config/index.ts
|
|
18446
19031
|
function getParser(opts = {}) {
|
|
18447
19032
|
return opts.playcademy ? playcademyParser : timebackParser;
|
|
18448
19033
|
}
|
|
18449
19034
|
|
|
19035
|
+
// ../internal/cli-infra/src/sensors/infer.ts
|
|
19036
|
+
function asRecord(value) {
|
|
19037
|
+
return typeof value === "object" && value !== null ? value : undefined;
|
|
19038
|
+
}
|
|
19039
|
+
function extractCourseIdCandidates(event) {
|
|
19040
|
+
const candidates = new Set;
|
|
19041
|
+
const obj = asRecord(event.object);
|
|
19042
|
+
const course = obj ? asRecord(obj.course) : undefined;
|
|
19043
|
+
const rawCourseId = course?.id;
|
|
19044
|
+
if (typeof rawCourseId === "string" && rawCourseId.length > 0) {
|
|
19045
|
+
candidates.add(rawCourseId);
|
|
19046
|
+
const lastSlash = rawCourseId.lastIndexOf("/");
|
|
19047
|
+
if (lastSlash >= 0 && lastSlash < rawCourseId.length - 1) {
|
|
19048
|
+
candidates.add(rawCourseId.slice(lastSlash + 1));
|
|
19049
|
+
}
|
|
19050
|
+
const coursesMarker = "/courses/";
|
|
19051
|
+
const idx = rawCourseId.indexOf(coursesMarker);
|
|
19052
|
+
if (idx >= 0) {
|
|
19053
|
+
const suffix = rawCourseId.slice(idx + coursesMarker.length);
|
|
19054
|
+
if (suffix)
|
|
19055
|
+
candidates.add(suffix);
|
|
19056
|
+
}
|
|
19057
|
+
}
|
|
19058
|
+
const extensions = asRecord(event.extensions);
|
|
19059
|
+
const extCourseId = extensions?.courseId;
|
|
19060
|
+
if (typeof extCourseId === "string" && extCourseId.length > 0) {
|
|
19061
|
+
candidates.add(extCourseId);
|
|
19062
|
+
}
|
|
19063
|
+
return [...candidates];
|
|
19064
|
+
}
|
|
19065
|
+
function toMillis(isoLike) {
|
|
19066
|
+
if (typeof isoLike !== "string") {
|
|
19067
|
+
return;
|
|
19068
|
+
}
|
|
19069
|
+
const ms = Date.parse(isoLike);
|
|
19070
|
+
return Number.isFinite(ms) ? ms : undefined;
|
|
19071
|
+
}
|
|
19072
|
+
async function inferSensorsFromCaliperEvents(client, options) {
|
|
19073
|
+
const { courseIds, maxEvents = 2000, pageSize = 2000, startDate } = options;
|
|
19074
|
+
const target = new Set(courseIds.filter(Boolean));
|
|
19075
|
+
if (target.size === 0) {
|
|
19076
|
+
return [];
|
|
19077
|
+
}
|
|
19078
|
+
const stats = new Map;
|
|
19079
|
+
const limit = Math.min(pageSize, maxEvents);
|
|
19080
|
+
const { events } = await client.caliper.events.list({ limit, startDate });
|
|
19081
|
+
const pageEvents = events ?? [];
|
|
19082
|
+
for (const raw of pageEvents) {
|
|
19083
|
+
const sensor = raw.sensor;
|
|
19084
|
+
if (typeof sensor !== "string" || sensor.length === 0) {
|
|
19085
|
+
continue;
|
|
19086
|
+
}
|
|
19087
|
+
const candidates = extractCourseIdCandidates(raw);
|
|
19088
|
+
const matches = candidates.some((c) => target.has(c));
|
|
19089
|
+
if (!matches) {
|
|
19090
|
+
continue;
|
|
19091
|
+
}
|
|
19092
|
+
const latestMs = toMillis(raw.eventTime);
|
|
19093
|
+
const current = stats.get(sensor);
|
|
19094
|
+
if (current) {
|
|
19095
|
+
current.count += 1;
|
|
19096
|
+
if (latestMs !== undefined) {
|
|
19097
|
+
current.latestMs = Math.max(current.latestMs ?? 0, latestMs);
|
|
19098
|
+
}
|
|
19099
|
+
} else {
|
|
19100
|
+
stats.set(sensor, { count: 1, latestMs });
|
|
19101
|
+
}
|
|
19102
|
+
}
|
|
19103
|
+
const sorted = [...stats.entries()].sort((a, b3) => {
|
|
19104
|
+
const countDiff = b3[1].count - a[1].count;
|
|
19105
|
+
if (countDiff !== 0)
|
|
19106
|
+
return countDiff;
|
|
19107
|
+
return (b3[1].latestMs ?? 0) - (a[1].latestMs ?? 0);
|
|
19108
|
+
}).map(([sensor]) => sensor);
|
|
19109
|
+
return sorted;
|
|
19110
|
+
}
|
|
19111
|
+
|
|
18450
19112
|
// ../internal/cli-infra/src/search/search.ts
|
|
18451
19113
|
function searchCourses(client, query, max = 50) {
|
|
18452
19114
|
return client.oneroster.courses.listAll({
|
|
@@ -18469,11 +19131,11 @@ async function promptSelectEnv(configuredEnvs) {
|
|
|
18469
19131
|
}
|
|
18470
19132
|
async function promptAppName() {
|
|
18471
19133
|
const name = await he({
|
|
18472
|
-
message: "
|
|
19134
|
+
message: "Search for your app",
|
|
18473
19135
|
placeholder: "My Timeback App",
|
|
18474
19136
|
validate: (value) => {
|
|
18475
19137
|
if (!value.trim())
|
|
18476
|
-
return "
|
|
19138
|
+
return "Please enter a search term";
|
|
18477
19139
|
}
|
|
18478
19140
|
});
|
|
18479
19141
|
if (pD(name))
|
|
@@ -18578,6 +19240,48 @@ async function selectCourses(client, initialResults, filterFn) {
|
|
|
18578
19240
|
results = filter(moreResults);
|
|
18579
19241
|
}
|
|
18580
19242
|
}
|
|
19243
|
+
async function enrichCoursesWithLaunchUrls(client, courses) {
|
|
19244
|
+
if (courses.length === 0)
|
|
19245
|
+
return { courses, inferredSensors: [] };
|
|
19246
|
+
const s = Y2();
|
|
19247
|
+
let didStop = false;
|
|
19248
|
+
const stopOnce = (message) => {
|
|
19249
|
+
if (didStop)
|
|
19250
|
+
return;
|
|
19251
|
+
s.stop(message);
|
|
19252
|
+
didStop = true;
|
|
19253
|
+
};
|
|
19254
|
+
s.start("Fetching course details...");
|
|
19255
|
+
const enriched = [];
|
|
19256
|
+
let inferredSensors = [];
|
|
19257
|
+
try {
|
|
19258
|
+
for (const course of courses) {
|
|
19259
|
+
const courseId = course.ids?.staging ?? course.ids?.production;
|
|
19260
|
+
if (!courseId) {
|
|
19261
|
+
enriched.push(course);
|
|
19262
|
+
continue;
|
|
19263
|
+
}
|
|
19264
|
+
const launchUrl = await inferLaunchUrl(client, courseId);
|
|
19265
|
+
if (launchUrl && !course.launchUrl) {
|
|
19266
|
+
enriched.push({ ...course, launchUrl });
|
|
19267
|
+
} else {
|
|
19268
|
+
enriched.push(course);
|
|
19269
|
+
}
|
|
19270
|
+
}
|
|
19271
|
+
const courseIds = enriched.map((c) => c.ids?.staging ?? c.ids?.production).filter((id) => typeof id === "string" && id.length > 0);
|
|
19272
|
+
if (courseIds.length > 0) {
|
|
19273
|
+
const startDate = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString();
|
|
19274
|
+
try {
|
|
19275
|
+
inferredSensors = await inferSensorsFromCaliperEvents(client, { courseIds, startDate });
|
|
19276
|
+
} catch {}
|
|
19277
|
+
}
|
|
19278
|
+
stopOnce("Course details loaded");
|
|
19279
|
+
return { courses: enriched, inferredSensors };
|
|
19280
|
+
} catch (error48) {
|
|
19281
|
+
stopOnce("Failed to load course details");
|
|
19282
|
+
throw error48;
|
|
19283
|
+
}
|
|
19284
|
+
}
|
|
18581
19285
|
async function searchAndSelectCourses(options) {
|
|
18582
19286
|
const { client, environment, appName: existingAppName, excludeCourseIds = [] } = options;
|
|
18583
19287
|
const filterExcluded = (courses) => {
|
|
@@ -18600,19 +19304,20 @@ async function searchAndSelectCourses(options) {
|
|
|
18600
19304
|
return { success: false, cancelled: true };
|
|
18601
19305
|
}
|
|
18602
19306
|
const courseConfigs = courses.map((c) => toCourseConfig(c, environment));
|
|
18603
|
-
|
|
19307
|
+
const { courses: enrichedConfigs, inferredSensors } = await enrichCoursesWithLaunchUrls(client, courseConfigs);
|
|
18604
19308
|
return {
|
|
18605
19309
|
success: true,
|
|
18606
19310
|
appName,
|
|
18607
|
-
courses:
|
|
18608
|
-
environment
|
|
19311
|
+
courses: enrichedConfigs,
|
|
19312
|
+
environment,
|
|
19313
|
+
inferredSensors
|
|
18609
19314
|
};
|
|
18610
19315
|
} catch (error48) {
|
|
18611
19316
|
const message = error48 instanceof Error ? error48.message : "Unknown error";
|
|
18612
19317
|
return { success: false, error: message };
|
|
18613
19318
|
}
|
|
18614
19319
|
}
|
|
18615
|
-
// ../internal/cli-infra/src/sensors/
|
|
19320
|
+
// ../internal/cli-infra/src/sensors/utils.ts
|
|
18616
19321
|
function isValidUrl(url2) {
|
|
18617
19322
|
try {
|
|
18618
19323
|
return Boolean(new URL(url2));
|
|
@@ -18620,15 +19325,60 @@ function isValidUrl(url2) {
|
|
|
18620
19325
|
return false;
|
|
18621
19326
|
}
|
|
18622
19327
|
}
|
|
19328
|
+
function getEffectiveLaunchUrl(course, config3, env2) {
|
|
19329
|
+
const envOverride = course.overrides?.[env2]?.launchUrl;
|
|
19330
|
+
if (envOverride)
|
|
19331
|
+
return envOverride;
|
|
19332
|
+
if (course.launchUrl)
|
|
19333
|
+
return course.launchUrl;
|
|
19334
|
+
return config3.launchUrl;
|
|
19335
|
+
}
|
|
19336
|
+
function getEffectiveSensorForCourse(course, config3, env2) {
|
|
19337
|
+
const envSensor = course.overrides?.[env2]?.sensor;
|
|
19338
|
+
if (envSensor) {
|
|
19339
|
+
return envSensor;
|
|
19340
|
+
}
|
|
19341
|
+
if (course.sensor) {
|
|
19342
|
+
return course.sensor;
|
|
19343
|
+
}
|
|
19344
|
+
if (config3.sensor) {
|
|
19345
|
+
return config3.sensor;
|
|
19346
|
+
}
|
|
19347
|
+
const launchUrl = getEffectiveLaunchUrl(course, config3, env2);
|
|
19348
|
+
if (launchUrl) {
|
|
19349
|
+
return deriveSensorFromLaunchUrl(launchUrl);
|
|
19350
|
+
}
|
|
19351
|
+
return;
|
|
19352
|
+
}
|
|
19353
|
+
function deriveEffectiveSensors(config3, env2) {
|
|
19354
|
+
const sensors = new Set;
|
|
19355
|
+
for (const course of config3.courses) {
|
|
19356
|
+
const sensor = getEffectiveSensorForCourse(course, config3, env2);
|
|
19357
|
+
if (sensor) {
|
|
19358
|
+
sensors.add(sensor);
|
|
19359
|
+
}
|
|
19360
|
+
}
|
|
19361
|
+
return Array.from(sensors);
|
|
19362
|
+
}
|
|
19363
|
+
|
|
19364
|
+
// ../internal/cli-infra/src/sensors/prompts.ts
|
|
19365
|
+
function deriveSensorFromLaunchUrl(launchUrl) {
|
|
19366
|
+
try {
|
|
19367
|
+
const url2 = new URL(launchUrl);
|
|
19368
|
+
return url2.origin;
|
|
19369
|
+
} catch {
|
|
19370
|
+
return;
|
|
19371
|
+
}
|
|
19372
|
+
}
|
|
18623
19373
|
async function promptSensor(options) {
|
|
18624
19374
|
const { defaultValue } = options ?? {};
|
|
18625
19375
|
const input = await he({
|
|
18626
|
-
message: "Sensor URL (
|
|
19376
|
+
message: "Sensor URL (for activity metrics)",
|
|
18627
19377
|
placeholder: "https://myapp.example.com",
|
|
18628
|
-
defaultValue,
|
|
19378
|
+
initialValue: defaultValue,
|
|
18629
19379
|
validate: (value) => {
|
|
18630
19380
|
if (!value.trim()) {
|
|
18631
|
-
return "Sensor URL is required
|
|
19381
|
+
return "Sensor URL is required";
|
|
18632
19382
|
}
|
|
18633
19383
|
if (!isValidUrl(value.trim())) {
|
|
18634
19384
|
return "Invalid URL format";
|
|
@@ -18641,25 +19391,6 @@ async function promptSensor(options) {
|
|
|
18641
19391
|
}
|
|
18642
19392
|
return input.trim();
|
|
18643
19393
|
}
|
|
18644
|
-
// ../internal/cli-infra/src/sensors/utils.ts
|
|
18645
|
-
function deriveSensorsFromConfig(config3) {
|
|
18646
|
-
const sensors = new Set;
|
|
18647
|
-
if (config3.sensor) {
|
|
18648
|
-
sensors.add(config3.sensor);
|
|
18649
|
-
}
|
|
18650
|
-
for (const course of config3.courses) {
|
|
18651
|
-
if (course.sensor) {
|
|
18652
|
-
sensors.add(course.sensor);
|
|
18653
|
-
}
|
|
18654
|
-
if (course.overrides?.staging?.sensor) {
|
|
18655
|
-
sensors.add(course.overrides.staging.sensor);
|
|
18656
|
-
}
|
|
18657
|
-
if (course.overrides?.production?.sensor) {
|
|
18658
|
-
sensors.add(course.overrides.production.sensor);
|
|
18659
|
-
}
|
|
18660
|
-
}
|
|
18661
|
-
return Array.from(sensors);
|
|
18662
|
-
}
|
|
18663
19394
|
// src/cli/commands/credentials/add.ts
|
|
18664
19395
|
async function addCredentials(options = {}) {
|
|
18665
19396
|
const { exitOnComplete = true, inline = false } = options;
|
|
@@ -18699,8 +19430,8 @@ async function addCredentials(options = {}) {
|
|
|
18699
19430
|
}
|
|
18700
19431
|
isOverwriting = true;
|
|
18701
19432
|
}
|
|
18702
|
-
const
|
|
18703
|
-
if (
|
|
19433
|
+
const result = await promptForCredentials(env2);
|
|
19434
|
+
if (result.status === "cancelled") {
|
|
18704
19435
|
if (!inline) {
|
|
18705
19436
|
if (isOverwriting) {
|
|
18706
19437
|
outro.info("Existing credentials unchanged");
|
|
@@ -18708,11 +19439,21 @@ async function addCredentials(options = {}) {
|
|
|
18708
19439
|
outro.cancelled();
|
|
18709
19440
|
}
|
|
18710
19441
|
}
|
|
18711
|
-
if (exitOnComplete)
|
|
19442
|
+
if (exitOnComplete) {
|
|
18712
19443
|
process.exit(0);
|
|
19444
|
+
}
|
|
18713
19445
|
return;
|
|
18714
19446
|
}
|
|
18715
|
-
|
|
19447
|
+
if (result.status === "error") {
|
|
19448
|
+
if (!inline) {
|
|
19449
|
+
outro.error("Credential setup failed");
|
|
19450
|
+
}
|
|
19451
|
+
if (exitOnComplete) {
|
|
19452
|
+
process.exit(1);
|
|
19453
|
+
}
|
|
19454
|
+
return;
|
|
19455
|
+
}
|
|
19456
|
+
await saveCredentials(env2, result.credentials);
|
|
18716
19457
|
M2.success(`${env2} credentials saved`);
|
|
18717
19458
|
savedCount++;
|
|
18718
19459
|
}
|
|
@@ -18962,8 +19703,10 @@ async function showCredentialsMenu(options = {}) {
|
|
|
18962
19703
|
}
|
|
18963
19704
|
}
|
|
18964
19705
|
// src/cli/commands/credentials/lib/initial.ts
|
|
18965
|
-
async function promptInitialCredentials() {
|
|
18966
|
-
|
|
19706
|
+
async function promptInitialCredentials(options = {}) {
|
|
19707
|
+
if (!options.skipIntro) {
|
|
19708
|
+
intro("Timeback Studio");
|
|
19709
|
+
}
|
|
18967
19710
|
Me("No credentials found. You need to configure at least one environment.", "First-time setup");
|
|
18968
19711
|
const environments = await fe({
|
|
18969
19712
|
message: "Which environments would you like to configure?",
|
|
@@ -18977,20 +19720,27 @@ async function promptInitialCredentials() {
|
|
|
18977
19720
|
outro.cancelled();
|
|
18978
19721
|
process.exit(0);
|
|
18979
19722
|
}
|
|
19723
|
+
const configuredEnvs = [];
|
|
18980
19724
|
for (const env2 of environments) {
|
|
18981
|
-
const
|
|
18982
|
-
if (
|
|
18983
|
-
|
|
18984
|
-
|
|
19725
|
+
const result = await promptForCredentials(env2);
|
|
19726
|
+
if (result.status === "cancelled") {
|
|
19727
|
+
outro.cancelled();
|
|
19728
|
+
process.exit(0);
|
|
19729
|
+
}
|
|
19730
|
+
if (result.status === "error") {
|
|
19731
|
+
outro.error("Credential setup failed");
|
|
19732
|
+
process.exit(1);
|
|
18985
19733
|
}
|
|
19734
|
+
await saveCredentials(env2, result.credentials);
|
|
19735
|
+
M2.success(`${env2} credentials saved`);
|
|
19736
|
+
configuredEnvs.push(env2);
|
|
18986
19737
|
}
|
|
18987
|
-
|
|
18988
|
-
let defaultEnv;
|
|
19738
|
+
let selectedEnv;
|
|
18989
19739
|
if (configuredEnvs.length === 1) {
|
|
18990
|
-
|
|
19740
|
+
selectedEnv = configuredEnvs[0];
|
|
18991
19741
|
} else {
|
|
18992
19742
|
const selected = await ve({
|
|
18993
|
-
message: "Which environment
|
|
19743
|
+
message: "Which environment would you like to use for this session?",
|
|
18994
19744
|
options: configuredEnvs.map((env2) => ({
|
|
18995
19745
|
value: env2,
|
|
18996
19746
|
label: env2.charAt(0).toUpperCase() + env2.slice(1)
|
|
@@ -19000,11 +19750,10 @@ async function promptInitialCredentials() {
|
|
|
19000
19750
|
outro.cancelled();
|
|
19001
19751
|
process.exit(0);
|
|
19002
19752
|
}
|
|
19003
|
-
|
|
19753
|
+
selectedEnv = selected;
|
|
19004
19754
|
}
|
|
19005
|
-
await saveDefaultEnvironment(defaultEnv);
|
|
19006
19755
|
Me(`Saved to ${dim(getCredentialsPath())}`, green("Setup complete"));
|
|
19007
|
-
return
|
|
19756
|
+
return selectedEnv;
|
|
19008
19757
|
}
|
|
19009
19758
|
// src/config/constants.ts
|
|
19010
19759
|
var configValues = {
|
|
@@ -19151,54 +19900,61 @@ async function fetchCourses(creds, env2, ids) {
|
|
|
19151
19900
|
client.close();
|
|
19152
19901
|
}
|
|
19153
19902
|
}
|
|
19154
|
-
|
|
19155
|
-
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
|
|
19159
|
-
|
|
19160
|
-
|
|
19161
|
-
|
|
19903
|
+
function isManagedCourse(course) {
|
|
19904
|
+
const managedBy = course.metadata?.managedBy;
|
|
19905
|
+
return typeof managedBy === "string" && managedBy.startsWith("timeback@");
|
|
19906
|
+
}
|
|
19907
|
+
async function checkCoursesManaged(creds, env2, ids) {
|
|
19908
|
+
if (ids.length === 0) {
|
|
19909
|
+
return { allManaged: true, unmanagedCourses: [] };
|
|
19910
|
+
}
|
|
19911
|
+
const client = new TimebackClient2({
|
|
19912
|
+
env: env2,
|
|
19913
|
+
auth: { clientId: creds.clientId, clientSecret: creds.clientSecret }
|
|
19914
|
+
});
|
|
19915
|
+
try {
|
|
19916
|
+
const s = Y2();
|
|
19917
|
+
s.start(`Fetching remote context...`);
|
|
19918
|
+
const courses = await fetchCoursesByIds(client, ids);
|
|
19919
|
+
s.stop(`Remote context fetched`);
|
|
19920
|
+
const unmanagedCourses = [];
|
|
19921
|
+
const fetchedIds = new Set;
|
|
19922
|
+
const courseMap = new Map;
|
|
19923
|
+
for (const course of courses) {
|
|
19924
|
+
if (course.sourcedId) {
|
|
19925
|
+
fetchedIds.add(course.sourcedId);
|
|
19926
|
+
courseMap.set(course.sourcedId, course);
|
|
19927
|
+
}
|
|
19928
|
+
if (!isManagedCourse(course) && course.sourcedId) {
|
|
19929
|
+
unmanagedCourses.push({ id: course.sourcedId, title: course.title });
|
|
19930
|
+
}
|
|
19162
19931
|
}
|
|
19932
|
+
for (const id of ids) {
|
|
19933
|
+
if (!fetchedIds.has(id)) {
|
|
19934
|
+
unmanagedCourses.push({ id });
|
|
19935
|
+
}
|
|
19936
|
+
}
|
|
19937
|
+
const allManaged = unmanagedCourses.length === 0;
|
|
19938
|
+
return { allManaged, unmanagedCourses };
|
|
19939
|
+
} finally {
|
|
19940
|
+
client.close();
|
|
19163
19941
|
}
|
|
19164
|
-
return credentials;
|
|
19165
19942
|
}
|
|
19166
|
-
|
|
19167
|
-
|
|
19168
|
-
|
|
19169
|
-
|
|
19170
|
-
if (saved)
|
|
19171
|
-
return saved;
|
|
19172
|
-
const configured = await getConfiguredEnvironments();
|
|
19173
|
-
return configured[0] ?? "staging";
|
|
19174
|
-
}
|
|
19175
|
-
async function handleCredentialSetup() {
|
|
19176
|
-
const selectedEnv = await promptInitialCredentials();
|
|
19177
|
-
if (!selectedEnv)
|
|
19943
|
+
// src/cli/lib/credentials.ts
|
|
19944
|
+
async function handleCredentialSetup(options = {}) {
|
|
19945
|
+
const selectedEnv = await promptInitialCredentials({ skipIntro: options.skipIntro });
|
|
19946
|
+
if (!selectedEnv) {
|
|
19178
19947
|
return null;
|
|
19948
|
+
}
|
|
19179
19949
|
const result = await loadCredentials(selectedEnv);
|
|
19180
|
-
if (!result.success)
|
|
19950
|
+
if (!result.success) {
|
|
19181
19951
|
return null;
|
|
19952
|
+
}
|
|
19182
19953
|
return {
|
|
19183
19954
|
credentials: { [selectedEnv]: result.credentials },
|
|
19184
|
-
|
|
19955
|
+
selectedEnvironment: selectedEnv
|
|
19185
19956
|
};
|
|
19186
19957
|
}
|
|
19187
|
-
async function ensureCredentials(env2, credentials) {
|
|
19188
|
-
const existing = credentials[env2];
|
|
19189
|
-
if (existing)
|
|
19190
|
-
return existing;
|
|
19191
|
-
intro("Timeback Studio");
|
|
19192
|
-
Me(`No credentials configured for ${env2}.`, "Credential setup required");
|
|
19193
|
-
const newCreds = await promptForCredentials(env2);
|
|
19194
|
-
if (!newCreds)
|
|
19195
|
-
return null;
|
|
19196
|
-
await saveCredentials(env2, newCreds);
|
|
19197
|
-
M2.success(`${env2} credentials saved`);
|
|
19198
|
-
Me(`Saved to ${dim(getCredentialsPath())}`, green("Setup complete"));
|
|
19199
|
-
credentials[env2] = newCreds;
|
|
19200
|
-
return newCreds;
|
|
19201
|
-
}
|
|
19202
19958
|
// src/cli/lib/onboarding/import.ts
|
|
19203
19959
|
import { TimebackClient as TimebackClient3 } from "@timeback/core";
|
|
19204
19960
|
async function promptImportApp(credentials, configuredEnvs) {
|
|
@@ -19260,6 +20016,46 @@ async function promptNoConfig(credentials, configuredEnvs, opts = {}) {
|
|
|
19260
20016
|
}
|
|
19261
20017
|
// src/cli/commands/serve/config.ts
|
|
19262
20018
|
import { basename as basename2 } from "node:path";
|
|
20019
|
+
async function resolveConfigSource(courseIds, opts, defaultEnvironment) {
|
|
20020
|
+
const parserOpts = { playcademy: opts.playcademy };
|
|
20021
|
+
let configuredEnvs = await getConfiguredEnvironments();
|
|
20022
|
+
let credentials = {};
|
|
20023
|
+
if (courseIds.length > 0) {
|
|
20024
|
+
if (configuredEnvs.length > 0) {
|
|
20025
|
+
credentials = await loadAllCredentials();
|
|
20026
|
+
}
|
|
20027
|
+
const resolved2 = await resolveConfig(courseIds, opts, credentials, configuredEnvs, defaultEnvironment);
|
|
20028
|
+
return resolved2 ? { resolved: resolved2, credentials, configuredEnvs } : null;
|
|
20029
|
+
}
|
|
20030
|
+
const configResult = await loadConfig2(parserOpts);
|
|
20031
|
+
if (configResult.success) {
|
|
20032
|
+
return {
|
|
20033
|
+
resolved: {
|
|
20034
|
+
userConfig: configResult.config,
|
|
20035
|
+
environment: defaultEnvironment,
|
|
20036
|
+
configFile: basename2(configResult.config.path)
|
|
20037
|
+
},
|
|
20038
|
+
credentials,
|
|
20039
|
+
configuredEnvs
|
|
20040
|
+
};
|
|
20041
|
+
}
|
|
20042
|
+
const isMissingConfig = configResult.error.includes("No") && configResult.error.includes("config found");
|
|
20043
|
+
if (!isMissingConfig) {
|
|
20044
|
+
printError3(configResult.error, parserOpts);
|
|
20045
|
+
return null;
|
|
20046
|
+
}
|
|
20047
|
+
if (configuredEnvs.length === 0) {
|
|
20048
|
+
const result = await handleCredentialSetup({ skipIntro: true });
|
|
20049
|
+
if (!result)
|
|
20050
|
+
return null;
|
|
20051
|
+
credentials = result.credentials;
|
|
20052
|
+
configuredEnvs = Object.keys(credentials);
|
|
20053
|
+
} else {
|
|
20054
|
+
credentials = await loadAllCredentials();
|
|
20055
|
+
}
|
|
20056
|
+
const resolved = await resolveConfig(courseIds, opts, credentials, configuredEnvs, defaultEnvironment);
|
|
20057
|
+
return resolved ? { resolved, credentials, configuredEnvs } : null;
|
|
20058
|
+
}
|
|
19263
20059
|
function buildUserConfigFromImport(result) {
|
|
19264
20060
|
const { name, courses, sensor } = result;
|
|
19265
20061
|
const courseIds = {
|
|
@@ -19301,10 +20097,11 @@ function buildUserConfigFromCourses(courses) {
|
|
|
19301
20097
|
};
|
|
19302
20098
|
}
|
|
19303
20099
|
async function resolveFromCourseIds(courseIds, env2, credentials, configuredEnvs) {
|
|
19304
|
-
const
|
|
19305
|
-
if (
|
|
20100
|
+
const ensureResult = await ensureCredentials({ env: env2, credentials, skipIntro: true });
|
|
20101
|
+
if (ensureResult.status !== "ok") {
|
|
19306
20102
|
return null;
|
|
19307
20103
|
}
|
|
20104
|
+
const creds = ensureResult.credentials;
|
|
19308
20105
|
const courses = await fetchCourses(creds, env2, courseIds);
|
|
19309
20106
|
if (courses.length === 0) {
|
|
19310
20107
|
M2.warn("No courses found for the provided IDs.");
|
|
@@ -19335,7 +20132,7 @@ async function resolveFromConfigOrImport(credentials, configuredEnvs, defaultEnv
|
|
|
19335
20132
|
}
|
|
19336
20133
|
const isMissingConfig = configResult.error.includes("No") && configResult.error.includes("config found");
|
|
19337
20134
|
if (isMissingConfig) {
|
|
19338
|
-
const importResult = await promptNoConfig(credentials, configuredEnvs);
|
|
20135
|
+
const importResult = await promptNoConfig(credentials, configuredEnvs, { skipIntro: true });
|
|
19339
20136
|
if (!importResult)
|
|
19340
20137
|
return null;
|
|
19341
20138
|
return {
|
|
@@ -19349,12 +20146,60 @@ async function resolveFromConfigOrImport(credentials, configuredEnvs, defaultEnv
|
|
|
19349
20146
|
function parseSensors(sensors) {
|
|
19350
20147
|
return sensors.split(",").map((s) => s.trim()).filter(Boolean);
|
|
19351
20148
|
}
|
|
19352
|
-
function
|
|
20149
|
+
function formatCourseExampleLines(courses, max = 3) {
|
|
20150
|
+
if (courses.length === 0)
|
|
20151
|
+
return [];
|
|
20152
|
+
const shown = courses.slice(0, max);
|
|
20153
|
+
const remaining = courses.length - shown.length;
|
|
20154
|
+
return [
|
|
20155
|
+
...shown.map((c) => `- ${cyan(c.title ?? c.id)}`),
|
|
20156
|
+
...remaining > 0 ? [`- ${dim(`(+${remaining} more)`)}`] : []
|
|
20157
|
+
];
|
|
20158
|
+
}
|
|
20159
|
+
async function resolveSensors(options) {
|
|
20160
|
+
const { config: config3, env: env2, opts, creds } = options;
|
|
19353
20161
|
if (opts.sensors) {
|
|
19354
20162
|
return parseSensors(opts.sensors);
|
|
19355
20163
|
}
|
|
19356
|
-
|
|
19357
|
-
|
|
20164
|
+
if (config3.sensor) {
|
|
20165
|
+
return [config3.sensor];
|
|
20166
|
+
}
|
|
20167
|
+
const courseIds = config3.courseIds[env2] ?? [];
|
|
20168
|
+
if (courseIds.length === 0) {
|
|
20169
|
+
return null;
|
|
20170
|
+
}
|
|
20171
|
+
const { allManaged, unmanagedCourses } = await checkCoursesManaged(creds, env2, courseIds);
|
|
20172
|
+
if (allManaged) {
|
|
20173
|
+
const derived = deriveEffectiveSensors(config3, env2);
|
|
20174
|
+
if (derived.length > 0) {
|
|
20175
|
+
return derived;
|
|
20176
|
+
}
|
|
20177
|
+
Me(["Add a top-level `sensor` to `timeback.config.json` or pass `--sensors`."].join(`
|
|
20178
|
+
`), "Next time");
|
|
20179
|
+
M2.error("Could not determine sensor(s) from config file");
|
|
20180
|
+
return null;
|
|
20181
|
+
}
|
|
20182
|
+
const count = unmanagedCourses.length;
|
|
20183
|
+
Me([
|
|
20184
|
+
`${count} ${pluralize(count, "course")} ${count === 1 ? "is" : "are"} unmanaged by Timeback CLI:`,
|
|
20185
|
+
"",
|
|
20186
|
+
...formatCourseExampleLines(unmanagedCourses)
|
|
20187
|
+
].join(`
|
|
20188
|
+
`), "Sensor required");
|
|
20189
|
+
const sensor = await promptSensor({
|
|
20190
|
+
defaultValue: config3.launchUrl ? deriveSensorFromLaunchUrl(config3.launchUrl) : undefined
|
|
20191
|
+
});
|
|
20192
|
+
if (sensor === undefined) {
|
|
20193
|
+
return null;
|
|
20194
|
+
}
|
|
20195
|
+
config3.sensor = sensor;
|
|
20196
|
+
if (config3.path?.endsWith(".json")) {
|
|
20197
|
+
const result = await updateTimebackConfigFile(config3.path, { sensor });
|
|
20198
|
+
if (result.success) {
|
|
20199
|
+
M2.success(`Saved sensor to ${basename2(config3.path)}`);
|
|
20200
|
+
}
|
|
20201
|
+
}
|
|
20202
|
+
return [sensor];
|
|
19358
20203
|
}
|
|
19359
20204
|
async function resolveConfig(courseIds, opts, credentials, configuredEnvs, defaultEnv) {
|
|
19360
20205
|
const parserOpts = { playcademy: opts.playcademy };
|
|
@@ -19362,7 +20207,59 @@ async function resolveConfig(courseIds, opts, credentials, configuredEnvs, defau
|
|
|
19362
20207
|
return resolved;
|
|
19363
20208
|
}
|
|
19364
20209
|
|
|
19365
|
-
//
|
|
20210
|
+
// src/cli/commands/serve/env.ts
|
|
20211
|
+
async function resolveServeEnvironment(options) {
|
|
20212
|
+
const { userConfig, hasEnvOverride, envOverride } = options;
|
|
20213
|
+
if (hasEnvOverride && envOverride) {
|
|
20214
|
+
return envOverride;
|
|
20215
|
+
}
|
|
20216
|
+
const stagingCount = userConfig.courseIds.staging?.length ?? 0;
|
|
20217
|
+
const productionCount = userConfig.courseIds.production?.length ?? 0;
|
|
20218
|
+
if (stagingCount === 0 && productionCount === 0) {
|
|
20219
|
+
return null;
|
|
20220
|
+
}
|
|
20221
|
+
if (stagingCount > 0 && productionCount === 0) {
|
|
20222
|
+
return "staging";
|
|
20223
|
+
}
|
|
20224
|
+
if (productionCount > 0 && stagingCount === 0) {
|
|
20225
|
+
return "production";
|
|
20226
|
+
}
|
|
20227
|
+
const selected = await ve({
|
|
20228
|
+
message: "Which environment would you like to use?",
|
|
20229
|
+
options: [
|
|
20230
|
+
{
|
|
20231
|
+
value: "staging",
|
|
20232
|
+
label: `Staging (${stagingCount} course${stagingCount === 1 ? "" : "s"})`
|
|
20233
|
+
},
|
|
20234
|
+
{
|
|
20235
|
+
value: "production",
|
|
20236
|
+
label: `Production (${productionCount} course${productionCount === 1 ? "" : "s"})`
|
|
20237
|
+
}
|
|
20238
|
+
]
|
|
20239
|
+
});
|
|
20240
|
+
if (isCancelled(selected)) {
|
|
20241
|
+
outro.cancelled();
|
|
20242
|
+
process.exit(0);
|
|
20243
|
+
}
|
|
20244
|
+
return selected;
|
|
20245
|
+
}
|
|
20246
|
+
async function promptEnvironmentForCourseIds(count) {
|
|
20247
|
+
const plural = count !== 1;
|
|
20248
|
+
const selected = await ve({
|
|
20249
|
+
message: plural ? "Which environment are these course IDs from?" : "Which environment is this course ID from?",
|
|
20250
|
+
options: [
|
|
20251
|
+
{ value: "staging", label: "Staging" },
|
|
20252
|
+
{ value: "production", label: "Production" }
|
|
20253
|
+
]
|
|
20254
|
+
});
|
|
20255
|
+
if (isCancelled(selected)) {
|
|
20256
|
+
outro.cancelled();
|
|
20257
|
+
process.exit(0);
|
|
20258
|
+
}
|
|
20259
|
+
return selected;
|
|
20260
|
+
}
|
|
20261
|
+
|
|
20262
|
+
// ../../node_modules/.bun/@hono+node-server@1.19.9+115df24086ffac64/node_modules/@hono/node-server/dist/index.mjs
|
|
19366
20263
|
import { createServer as createServerHTTP } from "http";
|
|
19367
20264
|
import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
|
|
19368
20265
|
import { Http2ServerRequest } from "http2";
|
|
@@ -19758,7 +20655,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
19758
20655
|
});
|
|
19759
20656
|
if (!chunk) {
|
|
19760
20657
|
if (i === 1) {
|
|
19761
|
-
await new Promise((
|
|
20658
|
+
await new Promise((resolve5) => setTimeout(resolve5));
|
|
19762
20659
|
maxReadCount = 3;
|
|
19763
20660
|
continue;
|
|
19764
20661
|
}
|
|
@@ -19896,7 +20793,7 @@ var serve = (options, listeningListener) => {
|
|
|
19896
20793
|
return server;
|
|
19897
20794
|
};
|
|
19898
20795
|
|
|
19899
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
20796
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/compose.js
|
|
19900
20797
|
var compose = (middleware, onError, onNotFound) => {
|
|
19901
20798
|
return (context, next) => {
|
|
19902
20799
|
let index = -1;
|
|
@@ -19940,10 +20837,10 @@ var compose = (middleware, onError, onNotFound) => {
|
|
|
19940
20837
|
};
|
|
19941
20838
|
};
|
|
19942
20839
|
|
|
19943
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
20840
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/request/constants.js
|
|
19944
20841
|
var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
|
|
19945
20842
|
|
|
19946
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
20843
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/utils/body.js
|
|
19947
20844
|
var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
|
|
19948
20845
|
const { all = false, dot = false } = options;
|
|
19949
20846
|
const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
|
|
@@ -20011,7 +20908,7 @@ var handleParsingNestedValues = (form, key, value) => {
|
|
|
20011
20908
|
});
|
|
20012
20909
|
};
|
|
20013
20910
|
|
|
20014
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
20911
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/utils/url.js
|
|
20015
20912
|
var splitPath = (path) => {
|
|
20016
20913
|
const paths = path.split("/");
|
|
20017
20914
|
if (paths[0] === "") {
|
|
@@ -20209,7 +21106,7 @@ var getQueryParams = (url2, key) => {
|
|
|
20209
21106
|
};
|
|
20210
21107
|
var decodeURIComponent_ = decodeURIComponent;
|
|
20211
21108
|
|
|
20212
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21109
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/request.js
|
|
20213
21110
|
var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
|
|
20214
21111
|
var HonoRequest = class {
|
|
20215
21112
|
raw;
|
|
@@ -20320,7 +21217,7 @@ var HonoRequest = class {
|
|
|
20320
21217
|
}
|
|
20321
21218
|
};
|
|
20322
21219
|
|
|
20323
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21220
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/utils/html.js
|
|
20324
21221
|
var HtmlEscapedCallbackPhase = {
|
|
20325
21222
|
Stringify: 1,
|
|
20326
21223
|
BeforeStream: 2,
|
|
@@ -20358,7 +21255,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
|
|
|
20358
21255
|
}
|
|
20359
21256
|
};
|
|
20360
21257
|
|
|
20361
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21258
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/context.js
|
|
20362
21259
|
var TEXT_PLAIN = "text/plain; charset=UTF-8";
|
|
20363
21260
|
var setDefaultContentType = (contentType, headers) => {
|
|
20364
21261
|
return {
|
|
@@ -20524,7 +21421,7 @@ var Context = class {
|
|
|
20524
21421
|
};
|
|
20525
21422
|
};
|
|
20526
21423
|
|
|
20527
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21424
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router.js
|
|
20528
21425
|
var METHOD_NAME_ALL = "ALL";
|
|
20529
21426
|
var METHOD_NAME_ALL_LOWERCASE = "all";
|
|
20530
21427
|
var METHODS = ["get", "post", "put", "delete", "options", "patch"];
|
|
@@ -20532,10 +21429,10 @@ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is
|
|
|
20532
21429
|
var UnsupportedPathError = class extends Error {
|
|
20533
21430
|
};
|
|
20534
21431
|
|
|
20535
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21432
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/utils/constants.js
|
|
20536
21433
|
var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
|
|
20537
21434
|
|
|
20538
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21435
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/hono-base.js
|
|
20539
21436
|
var notFoundHandler = (c) => {
|
|
20540
21437
|
return c.text("404 Not Found", 404);
|
|
20541
21438
|
};
|
|
@@ -20754,7 +21651,7 @@ var Hono = class _Hono {
|
|
|
20754
21651
|
};
|
|
20755
21652
|
};
|
|
20756
21653
|
|
|
20757
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21654
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/reg-exp-router/matcher.js
|
|
20758
21655
|
var emptyParam = [];
|
|
20759
21656
|
function match(method, path) {
|
|
20760
21657
|
const matchers = this.buildAllMatchers();
|
|
@@ -20775,7 +21672,7 @@ function match(method, path) {
|
|
|
20775
21672
|
return match2(method, path);
|
|
20776
21673
|
}
|
|
20777
21674
|
|
|
20778
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21675
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/reg-exp-router/node.js
|
|
20779
21676
|
var LABEL_REG_EXP_STR = "[^/]+";
|
|
20780
21677
|
var ONLY_WILDCARD_REG_EXP_STR = ".*";
|
|
20781
21678
|
var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
|
|
@@ -20879,7 +21776,7 @@ var Node = class _Node {
|
|
|
20879
21776
|
}
|
|
20880
21777
|
};
|
|
20881
21778
|
|
|
20882
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21779
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/reg-exp-router/trie.js
|
|
20883
21780
|
var Trie = class {
|
|
20884
21781
|
#context = { varIndex: 0 };
|
|
20885
21782
|
#root = new Node;
|
|
@@ -20935,7 +21832,7 @@ var Trie = class {
|
|
|
20935
21832
|
}
|
|
20936
21833
|
};
|
|
20937
21834
|
|
|
20938
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
21835
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/reg-exp-router/router.js
|
|
20939
21836
|
var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
|
|
20940
21837
|
var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
20941
21838
|
function buildWildcardRegExp(path) {
|
|
@@ -21100,7 +21997,7 @@ var RegExpRouter = class {
|
|
|
21100
21997
|
}
|
|
21101
21998
|
};
|
|
21102
21999
|
|
|
21103
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
22000
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
|
|
21104
22001
|
var PreparedRegExpRouter = class {
|
|
21105
22002
|
name = "PreparedRegExpRouter";
|
|
21106
22003
|
#matchers;
|
|
@@ -21172,7 +22069,7 @@ var PreparedRegExpRouter = class {
|
|
|
21172
22069
|
match = match;
|
|
21173
22070
|
};
|
|
21174
22071
|
|
|
21175
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
22072
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/smart-router/router.js
|
|
21176
22073
|
var SmartRouter = class {
|
|
21177
22074
|
name = "SmartRouter";
|
|
21178
22075
|
#routers = [];
|
|
@@ -21227,7 +22124,7 @@ var SmartRouter = class {
|
|
|
21227
22124
|
}
|
|
21228
22125
|
};
|
|
21229
22126
|
|
|
21230
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
22127
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/trie-router/node.js
|
|
21231
22128
|
var emptyParams = /* @__PURE__ */ Object.create(null);
|
|
21232
22129
|
var Node2 = class _Node2 {
|
|
21233
22130
|
#methods;
|
|
@@ -21381,7 +22278,7 @@ var Node2 = class _Node2 {
|
|
|
21381
22278
|
}
|
|
21382
22279
|
};
|
|
21383
22280
|
|
|
21384
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
22281
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/router/trie-router/router.js
|
|
21385
22282
|
var TrieRouter = class {
|
|
21386
22283
|
name = "TrieRouter";
|
|
21387
22284
|
#node;
|
|
@@ -21403,7 +22300,7 @@ var TrieRouter = class {
|
|
|
21403
22300
|
}
|
|
21404
22301
|
};
|
|
21405
22302
|
|
|
21406
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
22303
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/hono.js
|
|
21407
22304
|
var Hono2 = class extends Hono {
|
|
21408
22305
|
constructor(options = {}) {
|
|
21409
22306
|
super(options);
|
|
@@ -21413,7 +22310,7 @@ var Hono2 = class extends Hono {
|
|
|
21413
22310
|
}
|
|
21414
22311
|
};
|
|
21415
22312
|
|
|
21416
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
22313
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/middleware/cors/index.js
|
|
21417
22314
|
var cors = (options) => {
|
|
21418
22315
|
const defaults = {
|
|
21419
22316
|
origin: "*",
|
|
@@ -21828,10 +22725,6 @@ class Logger {
|
|
|
21828
22725
|
function createLogger(options = {}) {
|
|
21829
22726
|
return new Logger(options);
|
|
21830
22727
|
}
|
|
21831
|
-
// ../internal/utils/src/shared/format.ts
|
|
21832
|
-
function pluralize(count, singular, plural) {
|
|
21833
|
-
return count === 1 ? singular : plural ?? `${singular}s`;
|
|
21834
|
-
}
|
|
21835
22728
|
// src/server/services/bootstrap.ts
|
|
21836
22729
|
var log = createLogger({ scope: "studio:service:bootstrap" });
|
|
21837
22730
|
|
|
@@ -21848,7 +22741,7 @@ class BootstrapService {
|
|
|
21848
22741
|
const courses = await this.fetchCourses(courseIds, errors3);
|
|
21849
22742
|
const courseStructure = await this.fetchCourseStructure(courses, errors3);
|
|
21850
22743
|
const [enrollmentData, enrichedComponentResources] = await Promise.all([
|
|
21851
|
-
this.fetchEnrollments(courseStructure.classes),
|
|
22744
|
+
this.fetchEnrollments(courseStructure.classes, errors3),
|
|
21852
22745
|
this.fetchResources(courseStructure.componentResources, errors3)
|
|
21853
22746
|
]);
|
|
21854
22747
|
const enrichedEnrollments = await this.enrichEnrollmentsWithUsers(enrollmentData, errors3);
|
|
@@ -21940,9 +22833,33 @@ class BootstrapService {
|
|
|
21940
22833
|
return enrollmentData.enrollments;
|
|
21941
22834
|
}
|
|
21942
22835
|
try {
|
|
21943
|
-
const
|
|
21944
|
-
|
|
22836
|
+
const batches = splitIntoBatches(studentUserIds);
|
|
22837
|
+
log.debug("Fetching users in batches", {
|
|
22838
|
+
totalIds: studentUserIds.length,
|
|
22839
|
+
batchCount: batches.length
|
|
21945
22840
|
});
|
|
22841
|
+
const batchResults = await Promise.allSettled(batches.map((batch) => this.client.oneroster.users.listAll({
|
|
22842
|
+
where: { sourcedId: { in: batch } }
|
|
22843
|
+
})));
|
|
22844
|
+
const failed = extractRejected(batchResults);
|
|
22845
|
+
if (failed.length === batches.length) {
|
|
22846
|
+
const firstReason = failed[0]?.reason;
|
|
22847
|
+
const message = firstReason?.message ?? String(firstReason);
|
|
22848
|
+
log.warn("All user batches failed", {
|
|
22849
|
+
failedCount: failed.length,
|
|
22850
|
+
totalBatches: batches.length,
|
|
22851
|
+
reasons: failed.map((r2) => r2.reason?.message ?? String(r2.reason))
|
|
22852
|
+
});
|
|
22853
|
+
errors3.push(createStudioError("USERS_FETCH_FAILED", message));
|
|
22854
|
+
} else if (failed.length > 0) {
|
|
22855
|
+
log.warn("Some user batches failed", {
|
|
22856
|
+
failedCount: failed.length,
|
|
22857
|
+
totalBatches: batches.length,
|
|
22858
|
+
reasons: failed.map((r2) => r2.reason?.message ?? String(r2.reason))
|
|
22859
|
+
});
|
|
22860
|
+
errors3.push(createStudioError("USERS_FETCH_PARTIAL", `${failed.length} of ${batches.length} user batches failed`));
|
|
22861
|
+
}
|
|
22862
|
+
const users = extractFulfilled(batchResults);
|
|
21946
22863
|
const userMap = new Map(users.map((u2) => [u2.sourcedId, u2]));
|
|
21947
22864
|
log.debug("Enriched enrollments with user details", { count: users.length });
|
|
21948
22865
|
return enrollmentData.enrollments.map((enrollment) => ({
|
|
@@ -21963,9 +22880,33 @@ class BootstrapService {
|
|
|
21963
22880
|
}
|
|
21964
22881
|
const uniqueResourceIds = [...new Set(resourceIds)];
|
|
21965
22882
|
try {
|
|
21966
|
-
const
|
|
21967
|
-
|
|
22883
|
+
const batches = splitIntoBatches(uniqueResourceIds);
|
|
22884
|
+
log.debug("Fetching resources in batches", {
|
|
22885
|
+
totalIds: uniqueResourceIds.length,
|
|
22886
|
+
batchCount: batches.length
|
|
21968
22887
|
});
|
|
22888
|
+
const batchResults = await Promise.allSettled(batches.map((batch) => this.client.oneroster.resources.listAll({
|
|
22889
|
+
where: { sourcedId: { in: batch } }
|
|
22890
|
+
})));
|
|
22891
|
+
const failed = extractRejected(batchResults);
|
|
22892
|
+
if (failed.length === batches.length) {
|
|
22893
|
+
const firstReason = failed[0]?.reason;
|
|
22894
|
+
const message = firstReason?.message ?? String(firstReason);
|
|
22895
|
+
log.warn("All resource batches failed", {
|
|
22896
|
+
failedCount: failed.length,
|
|
22897
|
+
totalBatches: batches.length,
|
|
22898
|
+
reasons: failed.map((r2) => r2.reason?.message ?? String(r2.reason))
|
|
22899
|
+
});
|
|
22900
|
+
errors3.push(createStudioError("RESOURCES_FETCH_FAILED", message));
|
|
22901
|
+
} else if (failed.length > 0) {
|
|
22902
|
+
log.warn("Some resource batches failed", {
|
|
22903
|
+
failedCount: failed.length,
|
|
22904
|
+
totalBatches: batches.length,
|
|
22905
|
+
reasons: failed.map((r2) => r2.reason?.message ?? String(r2.reason))
|
|
22906
|
+
});
|
|
22907
|
+
errors3.push(createStudioError("RESOURCES_FETCH_PARTIAL", `${failed.length} of ${batches.length} resource batches failed`));
|
|
22908
|
+
}
|
|
22909
|
+
const resources = extractFulfilled(batchResults);
|
|
21969
22910
|
const resourceMap = new Map(resources.map((r2) => [r2.sourcedId, r2]));
|
|
21970
22911
|
return componentResources.map((cr) => ({
|
|
21971
22912
|
...cr,
|
|
@@ -22008,8 +22949,10 @@ class BootstrapService {
|
|
|
22008
22949
|
return null;
|
|
22009
22950
|
}
|
|
22010
22951
|
}
|
|
22011
|
-
async fetchEnrollments(classes) {
|
|
22012
|
-
const classIds =
|
|
22952
|
+
async fetchEnrollments(classes, errors3) {
|
|
22953
|
+
const classIds = [
|
|
22954
|
+
...new Set(classes.map((c) => c.sourcedId).filter((id) => !!id))
|
|
22955
|
+
];
|
|
22013
22956
|
const enrollments = [];
|
|
22014
22957
|
const studentIds = new Set;
|
|
22015
22958
|
const teacherIds = new Set;
|
|
@@ -22018,11 +22961,35 @@ class BootstrapService {
|
|
|
22018
22961
|
return { enrollments, studentIds, teacherIds, studentsByClass };
|
|
22019
22962
|
}
|
|
22020
22963
|
try {
|
|
22021
|
-
const
|
|
22022
|
-
|
|
22023
|
-
|
|
22024
|
-
|
|
22964
|
+
const batches = splitIntoBatches(classIds);
|
|
22965
|
+
log.debug("Fetching enrollments in batches", {
|
|
22966
|
+
totalClassIds: classIds.length,
|
|
22967
|
+
batchCount: batches.length
|
|
22025
22968
|
});
|
|
22969
|
+
const batchResults = await Promise.allSettled(batches.map((batch) => this.client.oneroster.enrollments.listAll({
|
|
22970
|
+
where: {
|
|
22971
|
+
"class.sourcedId": { in: batch }
|
|
22972
|
+
}
|
|
22973
|
+
})));
|
|
22974
|
+
const failed = extractRejected(batchResults);
|
|
22975
|
+
if (failed.length === batches.length) {
|
|
22976
|
+
const firstReason = failed[0]?.reason;
|
|
22977
|
+
const message = firstReason?.message ?? String(firstReason);
|
|
22978
|
+
log.warn("All enrollment batches failed", {
|
|
22979
|
+
failedCount: failed.length,
|
|
22980
|
+
totalBatches: batches.length,
|
|
22981
|
+
reasons: failed.map((r2) => r2.reason?.message ?? String(r2.reason))
|
|
22982
|
+
});
|
|
22983
|
+
errors3.push(createStudioError("ENROLLMENTS_FETCH_FAILED", message));
|
|
22984
|
+
} else if (failed.length > 0) {
|
|
22985
|
+
log.warn("Some enrollment batches failed", {
|
|
22986
|
+
failedCount: failed.length,
|
|
22987
|
+
totalBatches: batches.length,
|
|
22988
|
+
reasons: failed.map((r2) => r2.reason?.message ?? String(r2.reason))
|
|
22989
|
+
});
|
|
22990
|
+
errors3.push(createStudioError("ENROLLMENTS_FETCH_PARTIAL", `${failed.length} of ${batches.length} enrollment batches failed`));
|
|
22991
|
+
}
|
|
22992
|
+
const fetchedEnrollments = extractFulfilled(batchResults);
|
|
22026
22993
|
enrollments.push(...fetchedEnrollments);
|
|
22027
22994
|
for (const enrollment of fetchedEnrollments) {
|
|
22028
22995
|
const userId = enrollment.user?.sourcedId;
|
|
@@ -22048,6 +23015,7 @@ class BootstrapService {
|
|
|
22048
23015
|
} catch (error48) {
|
|
22049
23016
|
const message = getErrorMessage(error48);
|
|
22050
23017
|
log.warn("Failed to fetch enrollments", { error: message });
|
|
23018
|
+
errors3.push(createStudioError("ENROLLMENTS_FETCH_FAILED", message));
|
|
22051
23019
|
}
|
|
22052
23020
|
return { enrollments, studentIds, teacherIds, studentsByClass };
|
|
22053
23021
|
}
|
|
@@ -22062,9 +23030,16 @@ class EnrollmentService {
|
|
|
22062
23030
|
this.client = client;
|
|
22063
23031
|
}
|
|
22064
23032
|
async enroll(options) {
|
|
22065
|
-
const { classId, userId } = options;
|
|
23033
|
+
const { classId, courseId, userId } = options;
|
|
22066
23034
|
const errors3 = [];
|
|
22067
|
-
|
|
23035
|
+
if (!classId && !courseId) {
|
|
23036
|
+
errors3.push(createStudioError("ENV_INVALID", "Either classId or courseId is required"));
|
|
23037
|
+
return { success: false, errors: errors3 };
|
|
23038
|
+
}
|
|
23039
|
+
if (courseId && !classId) {
|
|
23040
|
+
return this.enrollViaCourse(userId, courseId, errors3);
|
|
23041
|
+
}
|
|
23042
|
+
log2.debug("Enrolling student via class", { classId, userId });
|
|
22068
23043
|
try {
|
|
22069
23044
|
const result = await this.client.oneroster.classes(classId).enroll({
|
|
22070
23045
|
sourcedId: userId,
|
|
@@ -22084,6 +23059,24 @@ class EnrollmentService {
|
|
|
22084
23059
|
return this.handleEnrollmentError(error48, "enroll", { classId, userId }, errors3);
|
|
22085
23060
|
}
|
|
22086
23061
|
}
|
|
23062
|
+
async enrollViaCourse(userId, courseId, errors3) {
|
|
23063
|
+
log2.debug("Enrolling student via course (EduBridge)", { courseId, userId });
|
|
23064
|
+
try {
|
|
23065
|
+
const enrollment = await this.client.edubridge.enrollments.enroll(userId, courseId);
|
|
23066
|
+
log2.debug("Student enrolled via EduBridge", {
|
|
23067
|
+
courseId,
|
|
23068
|
+
userId,
|
|
23069
|
+
enrollmentId: enrollment.id
|
|
23070
|
+
});
|
|
23071
|
+
return {
|
|
23072
|
+
success: true,
|
|
23073
|
+
enrollmentId: enrollment.id,
|
|
23074
|
+
errors: errors3
|
|
23075
|
+
};
|
|
23076
|
+
} catch (error48) {
|
|
23077
|
+
return this.handleEnrollmentError(error48, "enroll", { courseId, userId }, errors3);
|
|
23078
|
+
}
|
|
23079
|
+
}
|
|
22087
23080
|
async unenroll(options) {
|
|
22088
23081
|
const { enrollmentId } = options;
|
|
22089
23082
|
const errors3 = [];
|
|
@@ -22363,7 +23356,7 @@ class StudentSearchService {
|
|
|
22363
23356
|
const trimmedQuery = query.trim();
|
|
22364
23357
|
log5.debug("Searching students", { query: trimmedQuery, max });
|
|
22365
23358
|
try {
|
|
22366
|
-
const users = await this.client.oneroster.
|
|
23359
|
+
const users = await this.client.oneroster.users.listAll({
|
|
22367
23360
|
search: trimmedQuery,
|
|
22368
23361
|
where: { status: "active" },
|
|
22369
23362
|
max
|
|
@@ -22441,7 +23434,7 @@ function createManager(ctx) {
|
|
|
22441
23434
|
log6.debug("Manager ready", { environments: manager.names });
|
|
22442
23435
|
return manager;
|
|
22443
23436
|
}
|
|
22444
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
23437
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/helper/factory/index.js
|
|
22445
23438
|
var Factory = class {
|
|
22446
23439
|
initApp;
|
|
22447
23440
|
#defaultAppOptions;
|
|
@@ -22487,7 +23480,6 @@ function createEnvMiddleware(ctx, manager) {
|
|
|
22487
23480
|
}, 400);
|
|
22488
23481
|
}
|
|
22489
23482
|
if (!manager.has(env2)) {
|
|
22490
|
-
log7.warn("Environment not configured", { env: env2 });
|
|
22491
23483
|
const error48 = createStudioError("ENV_NOT_CONFIGURED", `Environment '${env2}' not configured`);
|
|
22492
23484
|
return c.json({
|
|
22493
23485
|
success: false,
|
|
@@ -22504,7 +23496,7 @@ function createEnvMiddleware(ctx, manager) {
|
|
|
22504
23496
|
await next();
|
|
22505
23497
|
});
|
|
22506
23498
|
}
|
|
22507
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
23499
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/utils/stream.js
|
|
22508
23500
|
var StreamingApi = class {
|
|
22509
23501
|
writer;
|
|
22510
23502
|
encoder;
|
|
@@ -22570,7 +23562,7 @@ var StreamingApi = class {
|
|
|
22570
23562
|
}
|
|
22571
23563
|
};
|
|
22572
23564
|
|
|
22573
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
23565
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/helper/streaming/utils.js
|
|
22574
23566
|
var isOldBunVersion = () => {
|
|
22575
23567
|
const version2 = typeof Bun !== "undefined" ? Bun.version : undefined;
|
|
22576
23568
|
if (version2 === undefined) {
|
|
@@ -22581,15 +23573,14 @@ var isOldBunVersion = () => {
|
|
|
22581
23573
|
return result;
|
|
22582
23574
|
};
|
|
22583
23575
|
|
|
22584
|
-
// ../../node_modules/.bun/hono@4.11.
|
|
23576
|
+
// ../../node_modules/.bun/hono@4.11.7/node_modules/hono/dist/helper/streaming/sse.js
|
|
22585
23577
|
var SSEStreamingApi = class extends StreamingApi {
|
|
22586
23578
|
constructor(writable, readable) {
|
|
22587
23579
|
super(writable, readable);
|
|
22588
23580
|
}
|
|
22589
23581
|
async writeSSE(message) {
|
|
22590
23582
|
const data = await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {});
|
|
22591
|
-
const dataLines = data.split(
|
|
22592
|
-
`).map((line) => {
|
|
23583
|
+
const dataLines = data.split(/\r\n|\r|\n/).map((line) => {
|
|
22593
23584
|
return `data: ${line}`;
|
|
22594
23585
|
}).join(`
|
|
22595
23586
|
`);
|
|
@@ -22605,7 +23596,7 @@ var SSEStreamingApi = class extends StreamingApi {
|
|
|
22605
23596
|
await this.write(sseData);
|
|
22606
23597
|
}
|
|
22607
23598
|
};
|
|
22608
|
-
var
|
|
23599
|
+
var run2 = async (stream, cb, onError) => {
|
|
22609
23600
|
try {
|
|
22610
23601
|
await cb(stream);
|
|
22611
23602
|
} catch (e2) {
|
|
@@ -22638,7 +23629,7 @@ var streamSSE = (c, cb, onError) => {
|
|
|
22638
23629
|
c.header("Content-Type", "text/event-stream");
|
|
22639
23630
|
c.header("Cache-Control", "no-cache");
|
|
22640
23631
|
c.header("Connection", "keep-alive");
|
|
22641
|
-
|
|
23632
|
+
run2(stream, cb, onError);
|
|
22642
23633
|
return c.newResponse(stream.responseReadable);
|
|
22643
23634
|
};
|
|
22644
23635
|
|
|
@@ -22732,8 +23723,11 @@ function runSSE(c, options) {
|
|
|
22732
23723
|
// src/server/controllers/enrollment.ts
|
|
22733
23724
|
var log9 = createLogger({ scope: "studio:route:enrollment" });
|
|
22734
23725
|
var enrollSchema = exports_external.object({
|
|
22735
|
-
|
|
22736
|
-
|
|
23726
|
+
userId: exports_external.string().min(1, "userId is required"),
|
|
23727
|
+
classId: exports_external.string().min(1).optional(),
|
|
23728
|
+
courseId: exports_external.string().min(1).optional()
|
|
23729
|
+
}).refine((data) => data.classId || data.courseId, {
|
|
23730
|
+
message: "Either classId or courseId is required"
|
|
22737
23731
|
});
|
|
22738
23732
|
var unenrollSchema = exports_external.object({
|
|
22739
23733
|
enrollmentId: exports_external.string().min(1, "enrollmentId is required")
|
|
@@ -22746,8 +23740,8 @@ async function handleEnroll(c) {
|
|
|
22746
23740
|
const error48 = createStudioError("ENV_INVALID", "Invalid request payload");
|
|
22747
23741
|
return c.json({ success: false, errors: [error48] }, 400);
|
|
22748
23742
|
}
|
|
22749
|
-
const { classId, userId } = parsedBody.data;
|
|
22750
|
-
const result = await enrollment.enroll({ classId, userId });
|
|
23743
|
+
const { classId, courseId, userId } = parsedBody.data;
|
|
23744
|
+
const result = await enrollment.enroll({ classId, courseId, userId });
|
|
22751
23745
|
return c.json(result, result.success ? 200 : 400);
|
|
22752
23746
|
}
|
|
22753
23747
|
async function handleUnenroll(c) {
|
|
@@ -22998,12 +23992,14 @@ function startServer(ctx, serverConfig, configFile) {
|
|
|
22998
23992
|
const app = createApp(ctx);
|
|
22999
23993
|
serve({ fetch: app.fetch, port: serverConfig.port }, (info) => {
|
|
23000
23994
|
const url2 = `http://localhost:${info.port}`;
|
|
23001
|
-
|
|
23002
|
-
console.log(
|
|
23003
|
-
console.log(
|
|
23004
|
-
console.log();
|
|
23005
|
-
console.log(
|
|
23006
|
-
console.log();
|
|
23995
|
+
const bar = gray("│");
|
|
23996
|
+
console.log(bar);
|
|
23997
|
+
console.log(bar);
|
|
23998
|
+
console.log(`${bar} ${green("┌")} ${bold(ctx.userConfig.name)} ${dim(`v${ctx.userConfig.version}`)}`);
|
|
23999
|
+
console.log(`${bar} ${green("└")} ${cyan(url2)}`);
|
|
24000
|
+
console.log(bar);
|
|
24001
|
+
console.log(`${bar} ${dim("press")} ${bold("h + enter")} ${dim("to show shortcuts")}`);
|
|
24002
|
+
console.log(bar);
|
|
23007
24003
|
if (configFile) {
|
|
23008
24004
|
M2.info(`Loaded ${greenBright(configFile)}`);
|
|
23009
24005
|
}
|
|
@@ -23012,33 +24008,128 @@ function startServer(ctx, serverConfig, configFile) {
|
|
|
23012
24008
|
}
|
|
23013
24009
|
|
|
23014
24010
|
// src/cli/commands/serve/index.ts
|
|
23015
|
-
async function
|
|
23016
|
-
const
|
|
24011
|
+
async function launchServer(serverConfig, userConfig, credentials, env2, opts, configFile) {
|
|
24012
|
+
const ensureResult = await ensureCredentials({ env: env2, credentials, skipIntro: true });
|
|
24013
|
+
if (ensureResult.status === "cancelled") {
|
|
24014
|
+
process.exit(0);
|
|
24015
|
+
}
|
|
24016
|
+
if (ensureResult.status === "error") {
|
|
24017
|
+
process.exit(1);
|
|
24018
|
+
}
|
|
24019
|
+
const creds = ensureResult.credentials;
|
|
24020
|
+
const derivedSensors = await resolveSensors({
|
|
24021
|
+
config: userConfig,
|
|
24022
|
+
env: env2,
|
|
24023
|
+
opts,
|
|
24024
|
+
creds
|
|
24025
|
+
});
|
|
24026
|
+
if (derivedSensors === null) {
|
|
24027
|
+
process.exit(1);
|
|
24028
|
+
}
|
|
24029
|
+
const ctx = {
|
|
24030
|
+
serverConfig,
|
|
24031
|
+
userConfig,
|
|
24032
|
+
credentials,
|
|
24033
|
+
defaultEnvironment: env2,
|
|
24034
|
+
derivedSensors
|
|
24035
|
+
};
|
|
24036
|
+
startServer(ctx, serverConfig, configFile);
|
|
24037
|
+
}
|
|
24038
|
+
async function handleCourseIdsCase(courseIds, opts, serverConfig) {
|
|
24039
|
+
const env2 = opts.env ?? await promptEnvironmentForCourseIds(courseIds.length);
|
|
23017
24040
|
let configuredEnvs = await getConfiguredEnvironments();
|
|
23018
|
-
let credentials;
|
|
23019
|
-
|
|
24041
|
+
let credentials = configuredEnvs.length > 0 ? await loadAllCredentials() : {};
|
|
24042
|
+
const resolvedResult = await resolveConfigSource(courseIds, opts, env2);
|
|
24043
|
+
if (!resolvedResult) {
|
|
24044
|
+
process.exit(1);
|
|
24045
|
+
}
|
|
24046
|
+
const { resolved, credentials: updatedCreds, configuredEnvs: updatedEnvs } = resolvedResult;
|
|
24047
|
+
credentials = updatedCreds;
|
|
24048
|
+
configuredEnvs = updatedEnvs;
|
|
24049
|
+
if (Object.keys(credentials).length === 0 && configuredEnvs.length > 0) {
|
|
24050
|
+
credentials = await loadAllCredentials();
|
|
24051
|
+
}
|
|
24052
|
+
await launchServer(serverConfig, resolved.userConfig, credentials, env2, opts, resolved.configFile);
|
|
24053
|
+
}
|
|
24054
|
+
async function handleConfigFileCase(userConfig, configPath, opts, serverConfig) {
|
|
24055
|
+
const env2 = await resolveServeEnvironment({
|
|
24056
|
+
userConfig,
|
|
24057
|
+
hasEnvOverride: Boolean(opts.env),
|
|
24058
|
+
envOverride: opts.env
|
|
24059
|
+
});
|
|
24060
|
+
if (env2 === null) {
|
|
24061
|
+
Me([
|
|
24062
|
+
`Your config file has no course IDs for ${bold("staging")} or ${bold("production")}.`,
|
|
24063
|
+
"",
|
|
24064
|
+
`Run ${greenBright(bold("timeback resources push"))} to populate course IDs in your config.`,
|
|
24065
|
+
"",
|
|
24066
|
+
`Alternatively, run ${greenBright(bold("timeback studio <courseId...>"))}.`
|
|
24067
|
+
].join(`
|
|
24068
|
+
`), "Note");
|
|
24069
|
+
M2.error("Config incomplete");
|
|
24070
|
+
console.log("");
|
|
24071
|
+
process.exit(1);
|
|
24072
|
+
}
|
|
24073
|
+
const envCourseIds = userConfig.courseIds[env2] ?? [];
|
|
24074
|
+
if (envCourseIds.length === 0) {
|
|
24075
|
+
const otherEnv = env2 === "staging" ? "production" : "staging";
|
|
24076
|
+
Me([
|
|
24077
|
+
`Your config file has no course IDs for ${bold(env2)}.`,
|
|
24078
|
+
"",
|
|
24079
|
+
`Try: ${greenBright(bold(`timeback studio --env ${otherEnv}`))}`,
|
|
24080
|
+
"",
|
|
24081
|
+
`Or run ${greenBright(bold("timeback resources push"))} to populate IDs for ${bold(env2)}.`
|
|
24082
|
+
].join(`
|
|
24083
|
+
`), "Note");
|
|
24084
|
+
M2.error("Config incomplete");
|
|
24085
|
+
console.log("");
|
|
24086
|
+
process.exit(1);
|
|
24087
|
+
}
|
|
24088
|
+
const credentials = await loadAllCredentials();
|
|
24089
|
+
await launchServer(serverConfig, userConfig, credentials, env2, opts, configPath);
|
|
24090
|
+
}
|
|
24091
|
+
async function handleImportFlowCase(opts, serverConfig) {
|
|
24092
|
+
let configuredEnvs = await getConfiguredEnvironments();
|
|
24093
|
+
let credentials = {};
|
|
24094
|
+
let selectedEnv;
|
|
23020
24095
|
if (configuredEnvs.length === 0) {
|
|
23021
|
-
const result = await handleCredentialSetup();
|
|
23022
|
-
if (!result)
|
|
24096
|
+
const result = await handleCredentialSetup({ skipIntro: true });
|
|
24097
|
+
if (!result) {
|
|
23023
24098
|
process.exit(1);
|
|
24099
|
+
}
|
|
23024
24100
|
credentials = result.credentials;
|
|
23025
|
-
defaultEnvironment = result.defaultEnvironment;
|
|
23026
24101
|
configuredEnvs = Object.keys(credentials);
|
|
24102
|
+
selectedEnv = result.selectedEnvironment;
|
|
23027
24103
|
} else {
|
|
23028
24104
|
credentials = await loadAllCredentials();
|
|
23029
|
-
defaultEnvironment = await resolveDefaultEnvironment(opts.env);
|
|
23030
24105
|
}
|
|
23031
|
-
const
|
|
23032
|
-
|
|
24106
|
+
const env2 = selectedEnv ?? configuredEnvs[0] ?? "staging";
|
|
24107
|
+
const resolvedResult = await resolveConfigSource([], opts, env2);
|
|
24108
|
+
if (!resolvedResult) {
|
|
23033
24109
|
process.exit(1);
|
|
23034
|
-
|
|
23035
|
-
|
|
23036
|
-
|
|
23037
|
-
|
|
23038
|
-
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
|
|
24110
|
+
}
|
|
24111
|
+
const { resolved } = resolvedResult;
|
|
24112
|
+
await launchServer(serverConfig, resolved.userConfig, credentials, env2, opts, resolved.configFile);
|
|
24113
|
+
}
|
|
24114
|
+
async function serveCommand(courseIds, opts) {
|
|
24115
|
+
intro("Timeback Studio");
|
|
24116
|
+
const serverConfig = getServerConfig();
|
|
24117
|
+
const parserOpts = { playcademy: opts.playcademy };
|
|
24118
|
+
if (courseIds.length > 0) {
|
|
24119
|
+
await handleCourseIdsCase(courseIds, opts, serverConfig);
|
|
24120
|
+
return;
|
|
24121
|
+
}
|
|
24122
|
+
const configResult = await loadConfig2(parserOpts);
|
|
24123
|
+
if (configResult.success) {
|
|
24124
|
+
await handleConfigFileCase(configResult.config, getRelativeConfigPath(configResult.config.path), opts, serverConfig);
|
|
24125
|
+
return;
|
|
24126
|
+
}
|
|
24127
|
+
const isMissingConfig = configResult.error.includes("No") && configResult.error.includes("config found");
|
|
24128
|
+
if (!isMissingConfig) {
|
|
24129
|
+
M2.error(configResult.error);
|
|
24130
|
+
process.exit(1);
|
|
24131
|
+
}
|
|
24132
|
+
await handleImportFlowCase(opts, serverConfig);
|
|
23042
24133
|
}
|
|
23043
24134
|
|
|
23044
24135
|
// src/cli/index.ts
|