@tostudy-ai/cli 0.11.0 → 0.11.1
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/bin/cli.js +0 -0
- package/dist/cli.js +405 -97
- package/dist/cli.js.map +4 -4
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +16 -15
package/dist/cli.js
CHANGED
|
@@ -104,7 +104,7 @@ var require_picocolors = __commonJS({
|
|
|
104
104
|
}
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
// ../../node_modules/@parisgroup-ai/logger/dist/logger.base-
|
|
107
|
+
// ../../node_modules/@parisgroup-ai/logger/dist/logger.base-CG4i4G4l.mjs
|
|
108
108
|
function formatJson(entry) {
|
|
109
109
|
const { timestamp: timestamp2, level, message, service, environment, context, data, error: error49 } = entry;
|
|
110
110
|
const output3 = {
|
|
@@ -284,8 +284,8 @@ function extractErrorInfo(error49, includeStack) {
|
|
|
284
284
|
return info;
|
|
285
285
|
}
|
|
286
286
|
var import_picocolors, LOG_LEVELS, LEVEL_COLORS, LEVEL_WIDTH, SENSITIVE_FIELDS, sanitize, BaseLogger;
|
|
287
|
-
var
|
|
288
|
-
"../../node_modules/@parisgroup-ai/logger/dist/logger.base-
|
|
287
|
+
var init_logger_base_CG4i4G4l = __esm({
|
|
288
|
+
"../../node_modules/@parisgroup-ai/logger/dist/logger.base-CG4i4G4l.mjs"() {
|
|
289
289
|
import_picocolors = __toESM(require_picocolors(), 1);
|
|
290
290
|
LOG_LEVELS = {
|
|
291
291
|
trace: 0,
|
|
@@ -541,7 +541,7 @@ var init_logger_base_CHajMTDD = __esm({
|
|
|
541
541
|
}
|
|
542
542
|
});
|
|
543
543
|
|
|
544
|
-
// ../../node_modules/@parisgroup-ai/logger/dist/index.
|
|
544
|
+
// ../../node_modules/@parisgroup-ai/logger/dist/index.mjs
|
|
545
545
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
546
546
|
import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
547
547
|
import { join } from "node:path";
|
|
@@ -610,8 +610,8 @@ function createLogger(module, options) {
|
|
|
610
610
|
}
|
|
611
611
|
var asyncLocalStorage, ConsoleTransport, FileTransport, HttpTransport, SINGLETON_KEY, Logger, logger;
|
|
612
612
|
var init_dist = __esm({
|
|
613
|
-
"../../node_modules/@parisgroup-ai/logger/dist/index.
|
|
614
|
-
|
|
613
|
+
"../../node_modules/@parisgroup-ai/logger/dist/index.mjs"() {
|
|
614
|
+
init_logger_base_CG4i4G4l();
|
|
615
615
|
asyncLocalStorage = new AsyncLocalStorage();
|
|
616
616
|
ConsoleTransport = class {
|
|
617
617
|
log(entry, formatted) {
|
|
@@ -859,6 +859,21 @@ function createHttpProvider(apiUrl, token2) {
|
|
|
859
859
|
const res = await apiFetch(`${base}/courses`, token2);
|
|
860
860
|
return res.courses;
|
|
861
861
|
},
|
|
862
|
+
listCreatorCourses: async (filters) => {
|
|
863
|
+
const params = new URLSearchParams();
|
|
864
|
+
params.append("status", filters.status || "all");
|
|
865
|
+
if (filters.search) params.append("search", filters.search);
|
|
866
|
+
if (filters.sortBy) params.append("sortBy", filters.sortBy);
|
|
867
|
+
if (filters.sortOrder) params.append("sortOrder", filters.sortOrder);
|
|
868
|
+
if (filters.limit) params.append("limit", filters.limit.toString());
|
|
869
|
+
if (filters.offset) params.append("offset", filters.offset.toString());
|
|
870
|
+
if (filters.projectId) params.append("projectId", filters.projectId);
|
|
871
|
+
const res = await apiFetch(
|
|
872
|
+
`${base}/creator-courses?${params.toString()}`,
|
|
873
|
+
token2
|
|
874
|
+
);
|
|
875
|
+
return res.courses;
|
|
876
|
+
},
|
|
862
877
|
select: async (_userId, courseId) => {
|
|
863
878
|
const res = await apiFetch(`${base}/courses/select`, token2, {
|
|
864
879
|
method: "POST",
|
|
@@ -1265,12 +1280,16 @@ function formatCourseList(courses3) {
|
|
|
1265
1280
|
month: "short",
|
|
1266
1281
|
day: "numeric"
|
|
1267
1282
|
}) : null;
|
|
1268
|
-
|
|
1283
|
+
const archivedBadge = course.status === "archived" ? " [ARQUIVADO]" : "";
|
|
1284
|
+
lines.push(` ${idx + 1}. ${course.title}${archivedBadge}`);
|
|
1269
1285
|
lines.push(` ${bar}`);
|
|
1270
1286
|
lines.push(` Professor: ${course.creatorName}`);
|
|
1271
1287
|
if (enrolledDate) {
|
|
1272
1288
|
lines.push(` Inscrito em: ${enrolledDate}`);
|
|
1273
1289
|
}
|
|
1290
|
+
if (course.status === "archived") {
|
|
1291
|
+
lines.push(` \u26A0 Arquivado \u2014 somente leitura (use \`tostudy lesson\`)`);
|
|
1292
|
+
}
|
|
1274
1293
|
lines.push("");
|
|
1275
1294
|
});
|
|
1276
1295
|
lines.push("\u2192 tostudy select <n\xFAmero> para ativar um curso");
|
|
@@ -2303,7 +2322,8 @@ var init_errors_pt_br = __esm({
|
|
|
2303
2322
|
vaultNotFound: "\u274C Vault n\xE3o encontrado. Execute 'tostudy vault init' primeiro.\n",
|
|
2304
2323
|
logoutSuccess: "\n Deslogado com sucesso.\n",
|
|
2305
2324
|
workspaceCommandDescription: "Gerenciar workspace de estudo local",
|
|
2306
|
-
workspaceSetupDescription: "Criar estrutura do workspace para o curso ativo"
|
|
2325
|
+
workspaceSetupDescription: "Criar estrutura do workspace para o curso ativo",
|
|
2326
|
+
insufficientCredits: "\u274C Voc\xEA est\xE1 sem cr\xE9ditos. Cada resposta do tutor de IA consome cr\xE9ditos para cobrir o processamento. Recarregue em https://tostudy.ai/student/credits para continuar de onde parou.\n"
|
|
2307
2327
|
};
|
|
2308
2328
|
}
|
|
2309
2329
|
});
|
|
@@ -2320,7 +2340,8 @@ var init_errors_en_us = __esm({
|
|
|
2320
2340
|
vaultNotFound: "\u274C Vault not found. Run 'tostudy vault init' first.\n",
|
|
2321
2341
|
logoutSuccess: "\n Logged out successfully.\n",
|
|
2322
2342
|
workspaceCommandDescription: "Manage local study workspace",
|
|
2323
|
-
workspaceSetupDescription: "Create the workspace structure for the active course"
|
|
2343
|
+
workspaceSetupDescription: "Create the workspace structure for the active course",
|
|
2344
|
+
insufficientCredits: "\u274C You're out of credits. Every reply from the AI tutor uses credits to cover processing. Top up at https://tostudy.ai/student/credits to continue from where you stopped.\n"
|
|
2324
2345
|
};
|
|
2325
2346
|
}
|
|
2326
2347
|
});
|
|
@@ -2348,6 +2369,10 @@ function resolveLocale() {
|
|
|
2348
2369
|
function getErrors(locale) {
|
|
2349
2370
|
return BUNDLES[locale ?? resolveLocale()];
|
|
2350
2371
|
}
|
|
2372
|
+
function isInsufficientCreditsError(err) {
|
|
2373
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2374
|
+
return msg.includes("INSUFFICIENT_CREDITS");
|
|
2375
|
+
}
|
|
2351
2376
|
var BUNDLES, _cachedLocale;
|
|
2352
2377
|
var init_errors = __esm({
|
|
2353
2378
|
"src/errors/index.ts"() {
|
|
@@ -2544,7 +2569,7 @@ var CLI_VERSION;
|
|
|
2544
2569
|
var init_version = __esm({
|
|
2545
2570
|
"src/version.ts"() {
|
|
2546
2571
|
"use strict";
|
|
2547
|
-
CLI_VERSION = true ? "0.11.
|
|
2572
|
+
CLI_VERSION = true ? "0.11.1" : "0.7.1";
|
|
2548
2573
|
}
|
|
2549
2574
|
});
|
|
2550
2575
|
|
|
@@ -2947,16 +2972,24 @@ var init_courses2 = __esm({
|
|
|
2947
2972
|
init_guards();
|
|
2948
2973
|
init_formatter();
|
|
2949
2974
|
logger4 = createLogger("cli:courses");
|
|
2950
|
-
coursesCommand = new Command5("courses").description("List your enrolled courses with progress").option("--json", "Output structured JSON").action(async (opts) => {
|
|
2975
|
+
coursesCommand = new Command5("courses").description("List your enrolled courses with progress").option("--json", "Output structured JSON").option("--mine", "List only your own courses, including drafts").action(async (opts) => {
|
|
2951
2976
|
try {
|
|
2952
2977
|
const session = await requireSession();
|
|
2953
2978
|
const data = createHttpProvider(session.apiUrl, session.token);
|
|
2954
2979
|
const deps = { data, logger: logger4 };
|
|
2955
|
-
|
|
2980
|
+
let coursesToList;
|
|
2981
|
+
if (opts.mine) {
|
|
2982
|
+
coursesToList = await data.courses.listCreatorCourses({
|
|
2983
|
+
userId: session.userId,
|
|
2984
|
+
status: "all"
|
|
2985
|
+
});
|
|
2986
|
+
} else {
|
|
2987
|
+
coursesToList = await listCourses({ userId: session.userId }, deps);
|
|
2988
|
+
}
|
|
2956
2989
|
if (opts.json) {
|
|
2957
|
-
output(
|
|
2990
|
+
output(coursesToList, { json: true });
|
|
2958
2991
|
} else {
|
|
2959
|
-
output(formatCourseList(
|
|
2992
|
+
output(formatCourseList(coursesToList), { json: false });
|
|
2960
2993
|
}
|
|
2961
2994
|
} catch (err) {
|
|
2962
2995
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -28729,6 +28762,12 @@ var init_users = __esm({
|
|
|
28729
28762
|
// Stripe Integration
|
|
28730
28763
|
stripeCustomerId: varchar("stripe_customer_id", { length: 255 }),
|
|
28731
28764
|
// Stripe Customer ID (cus_xxx) for payment method reuse
|
|
28765
|
+
// Paris Group integration: server-to-server provisioning attribution.
|
|
28766
|
+
// Set by `POST /api/internal/v1/cohort-enrollments` so the same paris
|
|
28767
|
+
// participant maps idempotently to a single tostudy user, and outbound
|
|
28768
|
+
// webhooks can scope themselves to `provisioning_source='paris-immersion'`.
|
|
28769
|
+
provisioningSource: text("provisioning_source"),
|
|
28770
|
+
externalUserId: text("external_user_id"),
|
|
28732
28771
|
metadata: jsonb("metadata").$type().default({}),
|
|
28733
28772
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
28734
28773
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
@@ -28747,7 +28786,12 @@ var init_users = __esm({
|
|
|
28747
28786
|
// FEAT-754: Portfolio index for public portfolio queries
|
|
28748
28787
|
portfolioEnabledIdx: index("users_portfolio_enabled_idx").on(table.portfolioEnabled),
|
|
28749
28788
|
// Admin analytics: date-range queries on users.createdAt (gte/lte)
|
|
28750
|
-
createdAtIdx: index("users_created_at_idx").on(table.createdAt)
|
|
28789
|
+
createdAtIdx: index("users_created_at_idx").on(table.createdAt),
|
|
28790
|
+
// Paris Group integration: composite lookup for idempotent provisioning.
|
|
28791
|
+
externalIdIdx: index("idx_users_external_id").on(
|
|
28792
|
+
table.provisioningSource,
|
|
28793
|
+
table.externalUserId
|
|
28794
|
+
)
|
|
28751
28795
|
})
|
|
28752
28796
|
);
|
|
28753
28797
|
}
|
|
@@ -28888,6 +28932,8 @@ var init_user_preferences = __esm({
|
|
|
28888
28932
|
emailNewReplies: boolean("email_new_replies").default(true).notNull(),
|
|
28889
28933
|
/** Whether user wants push notifications for mentorship (via MCP) */
|
|
28890
28934
|
pushMentoria: boolean("push_mentoria").default(true).notNull(),
|
|
28935
|
+
// i18n nickname pilot column (dogfooding)
|
|
28936
|
+
nicknameI18n: jsonb("nickname_i18n").$type(),
|
|
28891
28937
|
// Timestamps
|
|
28892
28938
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
28893
28939
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
@@ -29071,6 +29117,20 @@ var init_course_categories = __esm({
|
|
|
29071
29117
|
}
|
|
29072
29118
|
});
|
|
29073
29119
|
|
|
29120
|
+
// ../../packages/database/src/schema/course-visibility.ts
|
|
29121
|
+
var courseVisibilityEnum;
|
|
29122
|
+
var init_course_visibility = __esm({
|
|
29123
|
+
"../../packages/database/src/schema/course-visibility.ts"() {
|
|
29124
|
+
"use strict";
|
|
29125
|
+
init_pg_core();
|
|
29126
|
+
courseVisibilityEnum = pgEnum("course_visibility", [
|
|
29127
|
+
"public",
|
|
29128
|
+
"unlisted",
|
|
29129
|
+
"private_allowlist"
|
|
29130
|
+
]);
|
|
29131
|
+
}
|
|
29132
|
+
});
|
|
29133
|
+
|
|
29074
29134
|
// ../../packages/database/src/schema/courses.ts
|
|
29075
29135
|
var courseStatusEnum, courseFormatEnum, courseLevelEnum, creatorReviewStatusEnum, studyChannelEnum, courses;
|
|
29076
29136
|
var init_courses3 = __esm({
|
|
@@ -29079,6 +29139,7 @@ var init_courses3 = __esm({
|
|
|
29079
29139
|
init_pg_core();
|
|
29080
29140
|
init_users();
|
|
29081
29141
|
init_course_categories();
|
|
29142
|
+
init_course_visibility();
|
|
29082
29143
|
courseStatusEnum = pgEnum("course_status", [
|
|
29083
29144
|
"draft",
|
|
29084
29145
|
"pending_review",
|
|
@@ -29111,6 +29172,7 @@ var init_courses3 = __esm({
|
|
|
29111
29172
|
type: varchar("type", { length: 50 }),
|
|
29112
29173
|
// "self-paced" | "with-mentorship"
|
|
29113
29174
|
status: courseStatusEnum("status").default("draft"),
|
|
29175
|
+
visibility: courseVisibilityEnum("visibility").default("public").notNull(),
|
|
29114
29176
|
featured: boolean("featured").default(false).notNull(),
|
|
29115
29177
|
verified: boolean("verified").default(false).notNull(),
|
|
29116
29178
|
isEssential: boolean("is_essential").default(false).notNull(),
|
|
@@ -29206,7 +29268,20 @@ var init_courses3 = __esm({
|
|
|
29206
29268
|
// Widened to 800 in BUG-1346 (GH #382) — `deriveCertificateSummary` can
|
|
29207
29269
|
// return up to 203 chars (truncated + "..."), and AI-path edge cases
|
|
29208
29270
|
// exceeded varchar(200) silently. 800 covers worst observed (~660) + buffer.
|
|
29209
|
-
certificateSummary: varchar("certificate_summary", { length: 800 })
|
|
29271
|
+
certificateSummary: varchar("certificate_summary", { length: 800 }),
|
|
29272
|
+
/**
|
|
29273
|
+
* paris-immersion onboarding gate: true quando o curso foi endossado
|
|
29274
|
+
* pela equipe Paris para ser servido como onboarding de turmas. Default
|
|
29275
|
+
* false. NÃO afeta o marketplace ou a publicação normal — apenas o
|
|
29276
|
+
* endpoint `/api/internal/v1/courses?tag=paris-onboarding&endorsed=true`
|
|
29277
|
+
* filtra por este campo.
|
|
29278
|
+
*
|
|
29279
|
+
* Auto-marcado true quando o creator está em `paris_authorized_creators`
|
|
29280
|
+
* E o curso tem `tags` contendo 'paris-onboarding' (ver application/paris-endorsement.ts).
|
|
29281
|
+
* Admins paris-immersion podem endossar manualmente via
|
|
29282
|
+
* POST /api/internal/v1/courses/:slug/endorse.
|
|
29283
|
+
*/
|
|
29284
|
+
parisEndorsed: boolean("paris_endorsed").default(false).notNull()
|
|
29210
29285
|
},
|
|
29211
29286
|
(table) => ({
|
|
29212
29287
|
creatorIdIdx: index("courses_creator_id_idx").on(table.creatorId),
|
|
@@ -29233,6 +29308,8 @@ var init_courses3 = __esm({
|
|
|
29233
29308
|
// B-tree for FIFO ordering
|
|
29234
29309
|
statusSubmittedIdx: index("courses_status_submitted_idx").on(table.status, table.submittedAt),
|
|
29235
29310
|
// Composite for queue queries
|
|
29311
|
+
visibilityIdx: index("courses_visibility_idx").on(table.visibility),
|
|
29312
|
+
statusVisibilityIdx: index("courses_status_visibility_idx").on(table.status, table.visibility),
|
|
29236
29313
|
// Course completeness tracking index
|
|
29237
29314
|
completenessStatusIdx: index("courses_completeness_status_idx").on(table.completenessStatus),
|
|
29238
29315
|
// Verified Seal Quality System - Indexes for quality metrics filtering
|
|
@@ -29770,6 +29847,9 @@ var init_badges = __esm({
|
|
|
29770
29847
|
// Link to specific module (for module badges)
|
|
29771
29848
|
isEssentialBadge: boolean("is_essential_badge").default(false).notNull(),
|
|
29772
29849
|
// Flag for essential course badges
|
|
29850
|
+
// i18n dynamic translation pilot columns (Expand pattern)
|
|
29851
|
+
nameI18n: jsonb("name_i18n").$type(),
|
|
29852
|
+
descriptionI18n: jsonb("description_i18n").$type(),
|
|
29773
29853
|
// Display
|
|
29774
29854
|
order: integer("order").notNull().default(0),
|
|
29775
29855
|
// Display order
|
|
@@ -30203,6 +30283,34 @@ var init_course_reports = __esm({
|
|
|
30203
30283
|
}
|
|
30204
30284
|
});
|
|
30205
30285
|
|
|
30286
|
+
// ../../packages/database/src/schema/cohorts.ts
|
|
30287
|
+
var cohorts;
|
|
30288
|
+
var init_cohorts = __esm({
|
|
30289
|
+
"../../packages/database/src/schema/cohorts.ts"() {
|
|
30290
|
+
"use strict";
|
|
30291
|
+
init_pg_core();
|
|
30292
|
+
cohorts = pgTable(
|
|
30293
|
+
"cohorts",
|
|
30294
|
+
{
|
|
30295
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
30296
|
+
slug: text("slug").notNull().unique(),
|
|
30297
|
+
name: text("name").notNull(),
|
|
30298
|
+
/** e.g. "paris-immersion" — namespace for the external system that owns this cohort. */
|
|
30299
|
+
source: text("source").notNull(),
|
|
30300
|
+
/** Stable identifier in the source system (e.g. immersion slug). */
|
|
30301
|
+
sourceExternalId: text("source_external_id").notNull(),
|
|
30302
|
+
startsAt: timestamp("starts_at", { withTimezone: true }).notNull(),
|
|
30303
|
+
endsAt: timestamp("ends_at", { withTimezone: true }).notNull(),
|
|
30304
|
+
metadata: jsonb("metadata").$type().notNull().default({}),
|
|
30305
|
+
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull()
|
|
30306
|
+
},
|
|
30307
|
+
(table) => ({
|
|
30308
|
+
sourceIdx: index("idx_cohorts_source").on(table.source, table.sourceExternalId)
|
|
30309
|
+
})
|
|
30310
|
+
);
|
|
30311
|
+
}
|
|
30312
|
+
});
|
|
30313
|
+
|
|
30206
30314
|
// ../../packages/database/src/schema/enrollments.ts
|
|
30207
30315
|
var enrollmentStatusEnum, enrollmentSourceEnum, exerciseEntryLevelEnum, EXERCISE_ENTRY_LEVELS, enrollments;
|
|
30208
30316
|
var init_enrollments = __esm({
|
|
@@ -30211,6 +30319,7 @@ var init_enrollments = __esm({
|
|
|
30211
30319
|
init_pg_core();
|
|
30212
30320
|
init_users();
|
|
30213
30321
|
init_courses3();
|
|
30322
|
+
init_cohorts();
|
|
30214
30323
|
enrollmentStatusEnum = pgEnum("enrollment_status", [
|
|
30215
30324
|
"active",
|
|
30216
30325
|
"preview",
|
|
@@ -30264,6 +30373,10 @@ var init_enrollments = __esm({
|
|
|
30264
30373
|
// adjusts via the `enrollments.setExerciseLevel` mutation.
|
|
30265
30374
|
entryLevel: exerciseEntryLevelEnum("entry_level").notNull().default("L4"),
|
|
30266
30375
|
currentLevel: exerciseEntryLevelEnum("current_level").notNull().default("L4"),
|
|
30376
|
+
// Paris Group integration: links a provisioned enrollment to its cohort.
|
|
30377
|
+
// Set when tostudy provisions an account via `POST /api/internal/v1/cohort-enrollments`.
|
|
30378
|
+
// Nullable for non-cohort enrollments (self-enrollment, subscriptions, etc.).
|
|
30379
|
+
cohortId: uuid("cohort_id").references(() => cohorts.id, { onDelete: "set null" }),
|
|
30267
30380
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
|
|
30268
30381
|
metadata: jsonb("metadata").$type().default({})
|
|
30269
30382
|
},
|
|
@@ -30282,7 +30395,9 @@ var init_enrollments = __esm({
|
|
|
30282
30395
|
courseCurrentLevelIdx: index("enrollments_course_current_level_idx").on(
|
|
30283
30396
|
table.courseId,
|
|
30284
30397
|
table.currentLevel
|
|
30285
|
-
)
|
|
30398
|
+
),
|
|
30399
|
+
// Paris Group integration: partial index for cohort lookups.
|
|
30400
|
+
cohortIdIdx: index("idx_enrollments_cohort_id").on(table.cohortId)
|
|
30286
30401
|
})
|
|
30287
30402
|
);
|
|
30288
30403
|
}
|
|
@@ -30443,6 +30558,29 @@ var init_course_index = __esm({
|
|
|
30443
30558
|
}
|
|
30444
30559
|
});
|
|
30445
30560
|
|
|
30561
|
+
// ../../packages/database/src/schema/paris-authorized-creators.ts
|
|
30562
|
+
var parisAuthorizedCreators;
|
|
30563
|
+
var init_paris_authorized_creators = __esm({
|
|
30564
|
+
"../../packages/database/src/schema/paris-authorized-creators.ts"() {
|
|
30565
|
+
"use strict";
|
|
30566
|
+
init_pg_core();
|
|
30567
|
+
init_users();
|
|
30568
|
+
parisAuthorizedCreators = pgTable(
|
|
30569
|
+
"paris_authorized_creators",
|
|
30570
|
+
{
|
|
30571
|
+
userId: uuid("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
|
|
30572
|
+
/** Quem aprovou (admin Paris). NULL se setado via seed/SQL direto. */
|
|
30573
|
+
authorizedBy: uuid("authorized_by").references(() => users.id, { onDelete: "set null" }),
|
|
30574
|
+
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
30575
|
+
notes: text("notes")
|
|
30576
|
+
},
|
|
30577
|
+
(table) => ({
|
|
30578
|
+
authorizedByIdx: index("idx_paris_authorized_creators_authorized_by").on(table.authorizedBy)
|
|
30579
|
+
})
|
|
30580
|
+
);
|
|
30581
|
+
}
|
|
30582
|
+
});
|
|
30583
|
+
|
|
30446
30584
|
// ../../packages/database/src/schema/enrollment-channel-changes.ts
|
|
30447
30585
|
var enrollmentChannelChanges;
|
|
30448
30586
|
var init_enrollment_channel_changes = __esm({
|
|
@@ -33693,6 +33831,8 @@ var init_mentorship_services = __esm({
|
|
|
33693
33831
|
// 30, 45, 60, 90
|
|
33694
33832
|
priceCents: integer("price_cents").notNull(),
|
|
33695
33833
|
// min 5000 for 1:1, 3000 for group/workshop
|
|
33834
|
+
currency: varchar("currency", { length: 3 }).notNull().default("BRL"),
|
|
33835
|
+
// ISO 4217 uppercase; Phase 1 threads through DTOs
|
|
33696
33836
|
priceCredits: integer("price_credits"),
|
|
33697
33837
|
// nullable during migration, NOT NULL after Phase 3
|
|
33698
33838
|
maxParticipants: integer("max_participants").default(1).notNull(),
|
|
@@ -33943,37 +34083,50 @@ var init_mentorship_packages = __esm({
|
|
|
33943
34083
|
init_users();
|
|
33944
34084
|
init_mentorship_services();
|
|
33945
34085
|
init_zod();
|
|
33946
|
-
mentorshipPackages2 = pgTable(
|
|
33947
|
-
|
|
33948
|
-
|
|
33949
|
-
|
|
33950
|
-
|
|
33951
|
-
|
|
33952
|
-
|
|
33953
|
-
|
|
33954
|
-
|
|
33955
|
-
|
|
33956
|
-
|
|
33957
|
-
|
|
33958
|
-
|
|
33959
|
-
|
|
33960
|
-
|
|
33961
|
-
|
|
33962
|
-
|
|
33963
|
-
|
|
33964
|
-
|
|
33965
|
-
|
|
33966
|
-
|
|
33967
|
-
|
|
33968
|
-
|
|
33969
|
-
|
|
33970
|
-
|
|
33971
|
-
|
|
33972
|
-
|
|
33973
|
-
|
|
33974
|
-
|
|
33975
|
-
|
|
33976
|
-
|
|
34086
|
+
mentorshipPackages2 = pgTable(
|
|
34087
|
+
"mentorship_packages",
|
|
34088
|
+
{
|
|
34089
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
34090
|
+
mentorId: uuid("mentor_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
34091
|
+
serviceId: uuid("service_id").references(() => mentorshipServices2.id, { onDelete: "cascade" }).notNull(),
|
|
34092
|
+
// Package configuration
|
|
34093
|
+
numSessions: integer("num_sessions").notNull(),
|
|
34094
|
+
// 4, 8, or 12 (enforced by check constraint)
|
|
34095
|
+
discountPercent: integer("discount_percent").notNull().default(0),
|
|
34096
|
+
// 0-50 (enforced by check constraint)
|
|
34097
|
+
validityMonths: integer("validity_months").notNull().default(6),
|
|
34098
|
+
// 3, 6, or 12
|
|
34099
|
+
// Calculated prices (stored for consistency and to avoid recalculation issues)
|
|
34100
|
+
pricePerSessionCents: integer("price_per_session_cents").notNull(),
|
|
34101
|
+
// Price per session after discount
|
|
34102
|
+
totalPriceCents: integer("total_price_cents").notNull(),
|
|
34103
|
+
// Total package price
|
|
34104
|
+
currency: varchar("currency", { length: 3 }).notNull().default("BRL"),
|
|
34105
|
+
// ISO 4217 uppercase; Phase 2 threads through DTOs (derived from service.currency)
|
|
34106
|
+
// Status
|
|
34107
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
34108
|
+
// Timestamps
|
|
34109
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
34110
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
34111
|
+
},
|
|
34112
|
+
(table) => ({
|
|
34113
|
+
mentorIdIdx: index("mentorship_packages_mentor_id_idx").on(table.mentorId),
|
|
34114
|
+
serviceIdIdx: index("mentorship_packages_service_id_idx").on(table.serviceId),
|
|
34115
|
+
isActiveIdx: index("mentorship_packages_is_active_idx").on(table.isActive),
|
|
34116
|
+
mentorServiceActiveIdx: index("mentorship_packages_mentor_service_active_idx").on(
|
|
34117
|
+
table.mentorId,
|
|
34118
|
+
table.serviceId,
|
|
34119
|
+
table.isActive
|
|
34120
|
+
),
|
|
34121
|
+
// Check constraints for business rules
|
|
34122
|
+
numSessionsCheck: check("num_sessions_check", sql`${table.numSessions} IN (4, 8, 12)`),
|
|
34123
|
+
discountPercentCheck: check(
|
|
34124
|
+
"discount_percent_check",
|
|
34125
|
+
sql`${table.discountPercent} >= 0 AND ${table.discountPercent} <= 50`
|
|
34126
|
+
),
|
|
34127
|
+
validityMonthsCheck: check("validity_months_check", sql`${table.validityMonths} IN (3, 6, 12)`)
|
|
34128
|
+
})
|
|
34129
|
+
);
|
|
33977
34130
|
PACKAGE_SESSION_OPTIONS = [4, 8, 12];
|
|
33978
34131
|
PACKAGE_VALIDITY_OPTIONS = [3, 6, 12];
|
|
33979
34132
|
MAX_DISCOUNT_PERCENT = 50;
|
|
@@ -34207,7 +34360,7 @@ var init_mentorship_transactions = __esm({
|
|
|
34207
34360
|
transactionType: mentorshipTransactionTypeEnum("transaction_type").default("session").notNull(),
|
|
34208
34361
|
packageId: uuid("package_id").references(() => mentorshipPackages2.id, { onDelete: "set null" }),
|
|
34209
34362
|
serviceId: uuid("service_id").references(() => mentorshipServices2.id, { onDelete: "set null" }),
|
|
34210
|
-
// Financial amounts in cents
|
|
34363
|
+
// Financial amounts in cents - Story 19.3: Split tracking
|
|
34211
34364
|
grossAmountCents: integer("gross_amount_cents").notNull(),
|
|
34212
34365
|
// Original price before discount
|
|
34213
34366
|
discountCents: integer("discount_cents").default(0).notNull(),
|
|
@@ -34216,6 +34369,8 @@ var init_mentorship_transactions = __esm({
|
|
|
34216
34369
|
// 15% of net amount
|
|
34217
34370
|
mentorPayoutCents: integer("mentor_payout_cents").notNull(),
|
|
34218
34371
|
// 85% of net amount (netAmountCents)
|
|
34372
|
+
currency: varchar("currency", { length: 3 }).notNull().default("BRL"),
|
|
34373
|
+
// ISO 4217 uppercase; Phase 3 threads through DTOs (derived from package.currency / service.currency)
|
|
34219
34374
|
// Transaction status
|
|
34220
34375
|
status: mentorshipTransactionStatusEnum("status").default("pending").notNull(),
|
|
34221
34376
|
// Stripe integration
|
|
@@ -34462,53 +34617,66 @@ var init_transactions = __esm({
|
|
|
34462
34617
|
init_pg_core();
|
|
34463
34618
|
init_courses3();
|
|
34464
34619
|
init_users();
|
|
34465
|
-
transactions2 = pgTable(
|
|
34466
|
-
|
|
34467
|
-
|
|
34468
|
-
|
|
34469
|
-
|
|
34470
|
-
|
|
34471
|
-
|
|
34472
|
-
|
|
34473
|
-
|
|
34474
|
-
|
|
34475
|
-
|
|
34476
|
-
|
|
34477
|
-
|
|
34478
|
-
|
|
34479
|
-
|
|
34480
|
-
|
|
34481
|
-
|
|
34482
|
-
|
|
34483
|
-
|
|
34484
|
-
|
|
34485
|
-
|
|
34486
|
-
|
|
34487
|
-
|
|
34488
|
-
|
|
34489
|
-
|
|
34490
|
-
|
|
34491
|
-
|
|
34492
|
-
|
|
34493
|
-
|
|
34494
|
-
|
|
34495
|
-
|
|
34496
|
-
|
|
34497
|
-
|
|
34498
|
-
|
|
34499
|
-
|
|
34500
|
-
|
|
34501
|
-
|
|
34502
|
-
|
|
34503
|
-
|
|
34504
|
-
|
|
34505
|
-
|
|
34506
|
-
|
|
34507
|
-
|
|
34508
|
-
|
|
34509
|
-
|
|
34510
|
-
|
|
34511
|
-
|
|
34620
|
+
transactions2 = pgTable(
|
|
34621
|
+
"transactions",
|
|
34622
|
+
{
|
|
34623
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
34624
|
+
// Stripe references
|
|
34625
|
+
stripePaymentIntentId: varchar("stripe_payment_intent_id", { length: 255 }).notNull().unique(),
|
|
34626
|
+
stripeTransferId: varchar("stripe_transfer_id", { length: 255 }),
|
|
34627
|
+
// Stripe Transfer ID (if separate transfer)
|
|
34628
|
+
// Foreign keys
|
|
34629
|
+
courseId: uuid("course_id").notNull().references(() => courses.id, { onDelete: "restrict" }),
|
|
34630
|
+
creatorId: uuid("creator_id").notNull().references(() => users.id, { onDelete: "restrict" }),
|
|
34631
|
+
studentId: uuid("student_id").notNull().references(() => users.id, { onDelete: "restrict" }),
|
|
34632
|
+
// Financial details (all amounts in cents)
|
|
34633
|
+
amount: integer("amount").notNull(),
|
|
34634
|
+
// Total amount charged
|
|
34635
|
+
currency: varchar("currency", { length: 3 }).notNull().default("BRL"),
|
|
34636
|
+
// ISO 4217 uppercase; seeded from Stripe charge.currency on webhook insert
|
|
34637
|
+
platformFee: integer("platform_fee").notNull(),
|
|
34638
|
+
// Amount kept by platform
|
|
34639
|
+
creatorPayout: integer("creator_payout").notNull(),
|
|
34640
|
+
// Amount transferred to creator
|
|
34641
|
+
stripeFee: integer("stripe_fee"),
|
|
34642
|
+
// Stripe processing fee (nullable, updated from webhook)
|
|
34643
|
+
netPlatformRevenue: integer("net_platform_revenue"),
|
|
34644
|
+
// platformFee - stripeFee
|
|
34645
|
+
// Transaction metadata
|
|
34646
|
+
type: varchar("type", { length: 20 }).notNull(),
|
|
34647
|
+
// 'mentoria' or 'self-paced'
|
|
34648
|
+
paymentMethod: varchar("payment_method", { length: 50 }),
|
|
34649
|
+
// 'card' or 'pix'
|
|
34650
|
+
status: varchar("status", { length: 20 }).notNull().default("pending"),
|
|
34651
|
+
// 'pending', 'succeeded', 'failed', 'refunded'
|
|
34652
|
+
// Timestamps
|
|
34653
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
34654
|
+
processedAt: timestamp("processed_at"),
|
|
34655
|
+
refundedAt: timestamp("refunded_at"),
|
|
34656
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
34657
|
+
},
|
|
34658
|
+
(table) => ({
|
|
34659
|
+
// Indexes for fast lookups
|
|
34660
|
+
stripePaymentIntentIdIdx: index("transactions_stripe_payment_intent_id_idx").on(
|
|
34661
|
+
table.stripePaymentIntentId
|
|
34662
|
+
),
|
|
34663
|
+
creatorIdIdx: index("transactions_creator_id_idx").on(table.creatorId),
|
|
34664
|
+
studentIdIdx: index("transactions_student_id_idx").on(table.studentId),
|
|
34665
|
+
statusIdx: index("transactions_status_idx").on(table.status),
|
|
34666
|
+
paymentMethodIdx: index("transactions_payment_method_idx").on(table.paymentMethod),
|
|
34667
|
+
// For PIX analytics
|
|
34668
|
+
createdAtIdx: index("transactions_created_at_idx").on(table.createdAt),
|
|
34669
|
+
// For analytics queries
|
|
34670
|
+
refundedAtIdx: index("transactions_refunded_at_idx").on(table.refundedAt),
|
|
34671
|
+
// Issue #4: Database Index Gaps - Composite index for refund lookups
|
|
34672
|
+
refundLookupIdx: index("transactions_refund_lookup_idx").on(
|
|
34673
|
+
table.courseId,
|
|
34674
|
+
table.studentId,
|
|
34675
|
+
table.status,
|
|
34676
|
+
table.createdAt
|
|
34677
|
+
)
|
|
34678
|
+
})
|
|
34679
|
+
);
|
|
34512
34680
|
}
|
|
34513
34681
|
});
|
|
34514
34682
|
|
|
@@ -36827,7 +36995,16 @@ var init_security_audit_log = __esm({
|
|
|
36827
36995
|
"admin.impersonate_start",
|
|
36828
36996
|
"admin.impersonate_end",
|
|
36829
36997
|
"admin.config_change",
|
|
36830
|
-
"admin.student_progress_reset"
|
|
36998
|
+
"admin.student_progress_reset",
|
|
36999
|
+
// Paris integration events (PR #575)
|
|
37000
|
+
"account.claimed_by_external",
|
|
37001
|
+
"account.claim_denied_by_policy",
|
|
37002
|
+
"user.created_by_external",
|
|
37003
|
+
"authorized_creator.added",
|
|
37004
|
+
"authorized_creator.add_attempt_unknown_user",
|
|
37005
|
+
"authorized_creator.removed",
|
|
37006
|
+
"course.paris_endorsed",
|
|
37007
|
+
"course.paris_endorsement_revoked"
|
|
36831
37008
|
]);
|
|
36832
37009
|
securityEventResultEnum = pgEnum("security_event_result", [
|
|
36833
37010
|
"success",
|
|
@@ -40896,6 +41073,80 @@ var init_brainstorm_knowledge_bases = __esm({
|
|
|
40896
41073
|
}
|
|
40897
41074
|
});
|
|
40898
41075
|
|
|
41076
|
+
// ../../packages/database/src/schema/course-allowlist.ts
|
|
41077
|
+
var courseAllowlist;
|
|
41078
|
+
var init_course_allowlist = __esm({
|
|
41079
|
+
"../../packages/database/src/schema/course-allowlist.ts"() {
|
|
41080
|
+
"use strict";
|
|
41081
|
+
init_pg_core();
|
|
41082
|
+
init_courses3();
|
|
41083
|
+
init_users();
|
|
41084
|
+
courseAllowlist = pgTable(
|
|
41085
|
+
"course_allowlist",
|
|
41086
|
+
{
|
|
41087
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
41088
|
+
courseId: uuid("course_id").references(() => courses.id, { onDelete: "cascade" }).notNull(),
|
|
41089
|
+
email: varchar("email", { length: 255 }).notNull(),
|
|
41090
|
+
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }),
|
|
41091
|
+
invitedBy: uuid("invited_by").references(() => users.id, {
|
|
41092
|
+
onDelete: "set null"
|
|
41093
|
+
}),
|
|
41094
|
+
invitedAt: timestamp("invited_at", { withTimezone: true }).defaultNow().notNull(),
|
|
41095
|
+
resolvedAt: timestamp("resolved_at", { withTimezone: true })
|
|
41096
|
+
},
|
|
41097
|
+
(table) => ({
|
|
41098
|
+
courseEmailUnique: uniqueIndex("course_allowlist_course_email_unique").on(
|
|
41099
|
+
table.courseId,
|
|
41100
|
+
table.email
|
|
41101
|
+
),
|
|
41102
|
+
courseIdIdx: index("course_allowlist_course_id_idx").on(table.courseId)
|
|
41103
|
+
// partial indexes (user_id IS NOT NULL / IS NULL) are created via raw SQL in the migration — see drizzle-kit $N gotcha in packages/database/AGENTS.md
|
|
41104
|
+
})
|
|
41105
|
+
);
|
|
41106
|
+
}
|
|
41107
|
+
});
|
|
41108
|
+
|
|
41109
|
+
// ../../node_modules/@parisgroup-ai/pg-backend/dist/idempotency-schema.mjs
|
|
41110
|
+
var pgBackendIdempotencyKeys;
|
|
41111
|
+
var init_idempotency_schema = __esm({
|
|
41112
|
+
"../../node_modules/@parisgroup-ai/pg-backend/dist/idempotency-schema.mjs"() {
|
|
41113
|
+
init_drizzle_orm();
|
|
41114
|
+
init_pg_core();
|
|
41115
|
+
pgBackendIdempotencyKeys = pgTable("pg_backend_idempotency_keys", {
|
|
41116
|
+
reservationId: uuid("reservation_id").primaryKey().defaultRandom(),
|
|
41117
|
+
idempotencyKey: text("idempotency_key").notNull(),
|
|
41118
|
+
resource: text("resource").notNull(),
|
|
41119
|
+
operation: text("operation").notNull(),
|
|
41120
|
+
fingerprint: text("fingerprint").notNull(),
|
|
41121
|
+
scopeKey: text("scope_key"),
|
|
41122
|
+
status: text("status").notNull(),
|
|
41123
|
+
response: jsonb("response"),
|
|
41124
|
+
reservedAt: timestamp("reserved_at", { withTimezone: true }).notNull().defaultNow(),
|
|
41125
|
+
committedAt: timestamp("committed_at", { withTimezone: true }),
|
|
41126
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull()
|
|
41127
|
+
}, (t) => ({
|
|
41128
|
+
uniqueKey: uniqueIndex("pg_backend_idempotency_unique").on(t.idempotencyKey, t.resource, t.operation, sql`COALESCE(${t.scopeKey}, '')`),
|
|
41129
|
+
expiresIdx: index("pg_backend_idempotency_expires").on(t.expiresAt),
|
|
41130
|
+
pendingIdx: index("pg_backend_idempotency_pending").on(t.status, t.reservedAt)
|
|
41131
|
+
}));
|
|
41132
|
+
}
|
|
41133
|
+
});
|
|
41134
|
+
|
|
41135
|
+
// ../../node_modules/@parisgroup-ai/pg-backend/dist/index.mjs
|
|
41136
|
+
var init_dist2 = __esm({
|
|
41137
|
+
"../../node_modules/@parisgroup-ai/pg-backend/dist/index.mjs"() {
|
|
41138
|
+
init_idempotency_schema();
|
|
41139
|
+
}
|
|
41140
|
+
});
|
|
41141
|
+
|
|
41142
|
+
// ../../packages/database/src/schema/idempotency.ts
|
|
41143
|
+
var init_idempotency = __esm({
|
|
41144
|
+
"../../packages/database/src/schema/idempotency.ts"() {
|
|
41145
|
+
"use strict";
|
|
41146
|
+
init_dist2();
|
|
41147
|
+
}
|
|
41148
|
+
});
|
|
41149
|
+
|
|
40899
41150
|
// ../../packages/database/src/schema/index.ts
|
|
40900
41151
|
var schema_exports = {};
|
|
40901
41152
|
__export(schema_exports, {
|
|
@@ -40943,6 +41194,7 @@ __export(schema_exports, {
|
|
|
40943
41194
|
challengeType: () => challengeType,
|
|
40944
41195
|
challenges: () => challenges,
|
|
40945
41196
|
challengesRelations: () => challengesRelations,
|
|
41197
|
+
cohorts: () => cohorts,
|
|
40946
41198
|
communityComments: () => communityComments2,
|
|
40947
41199
|
communityCommentsRelations: () => communityCommentsRelations2,
|
|
40948
41200
|
communityLikes: () => communityLikes2,
|
|
@@ -40968,6 +41220,7 @@ __export(schema_exports, {
|
|
|
40968
41220
|
couponUsagesRelations: () => couponUsagesRelations2,
|
|
40969
41221
|
coupons: () => coupons2,
|
|
40970
41222
|
couponsRelations: () => couponsRelations2,
|
|
41223
|
+
courseAllowlist: () => courseAllowlist,
|
|
40971
41224
|
courseAssets: () => courseAssets,
|
|
40972
41225
|
courseAssetsRelations: () => courseAssetsRelations,
|
|
40973
41226
|
courseCategories: () => courseCategories,
|
|
@@ -41000,6 +41253,7 @@ __export(schema_exports, {
|
|
|
41000
41253
|
courseValidations: () => courseValidations,
|
|
41001
41254
|
courseVideoPrompts: () => courseVideoPrompts,
|
|
41002
41255
|
courseVideoPromptsRelations: () => courseVideoPromptsRelations,
|
|
41256
|
+
courseVisibilityEnum: () => courseVisibilityEnum,
|
|
41003
41257
|
courses: () => courses,
|
|
41004
41258
|
coursesRelations: () => coursesRelations2,
|
|
41005
41259
|
creatorApplications: () => creatorApplications2,
|
|
@@ -41158,6 +41412,7 @@ __export(schema_exports, {
|
|
|
41158
41412
|
onboardingAnalytics: () => onboardingAnalytics2,
|
|
41159
41413
|
onboardingAnalyticsRelations: () => onboardingAnalyticsRelations2,
|
|
41160
41414
|
optimizerRoleEnum: () => optimizerRoleEnum,
|
|
41415
|
+
parisAuthorizedCreators: () => parisAuthorizedCreators,
|
|
41161
41416
|
parseSettingValue: () => parseSettingValue,
|
|
41162
41417
|
participantStatusEnum: () => participantStatusEnum,
|
|
41163
41418
|
pathCourses: () => pathCourses2,
|
|
@@ -41177,6 +41432,7 @@ __export(schema_exports, {
|
|
|
41177
41432
|
payoutWithdrawals: () => payoutWithdrawals,
|
|
41178
41433
|
payouts: () => payouts2,
|
|
41179
41434
|
payoutsRelations: () => payoutsRelations2,
|
|
41435
|
+
pgBackendIdempotencyKeys: () => pgBackendIdempotencyKeys,
|
|
41180
41436
|
pixKeyTypeEnum: () => pixKeyTypeEnum,
|
|
41181
41437
|
platformConfig: () => platformConfig,
|
|
41182
41438
|
platformFeeTypeEnum: () => platformFeeTypeEnum,
|
|
@@ -41367,6 +41623,8 @@ var init_schema3 = __esm({
|
|
|
41367
41623
|
"use strict";
|
|
41368
41624
|
init_auth_index();
|
|
41369
41625
|
init_course_index();
|
|
41626
|
+
init_cohorts();
|
|
41627
|
+
init_paris_authorized_creators();
|
|
41370
41628
|
init_enrollment_channel_changes();
|
|
41371
41629
|
init_badges();
|
|
41372
41630
|
init_user_badges();
|
|
@@ -41457,6 +41715,9 @@ var init_schema3 = __esm({
|
|
|
41457
41715
|
init_announcements();
|
|
41458
41716
|
init_creator_brainstorm();
|
|
41459
41717
|
init_brainstorm_knowledge_bases();
|
|
41718
|
+
init_course_visibility();
|
|
41719
|
+
init_course_allowlist();
|
|
41720
|
+
init_idempotency();
|
|
41460
41721
|
}
|
|
41461
41722
|
});
|
|
41462
41723
|
|
|
@@ -41469,6 +41730,14 @@ var init_check_module_unlocked = __esm({
|
|
|
41469
41730
|
}
|
|
41470
41731
|
});
|
|
41471
41732
|
|
|
41733
|
+
// ../../packages/database/src/utils/courses-filter.ts
|
|
41734
|
+
var init_courses_filter = __esm({
|
|
41735
|
+
"../../packages/database/src/utils/courses-filter.ts"() {
|
|
41736
|
+
"use strict";
|
|
41737
|
+
init_courses3();
|
|
41738
|
+
}
|
|
41739
|
+
});
|
|
41740
|
+
|
|
41472
41741
|
// ../../packages/database/src/utils/date-helpers.ts
|
|
41473
41742
|
var init_date_helpers = __esm({
|
|
41474
41743
|
"../../packages/database/src/utils/date-helpers.ts"() {
|
|
@@ -41494,6 +41763,7 @@ var init_src4 = __esm({
|
|
|
41494
41763
|
init_schema3();
|
|
41495
41764
|
init_schema3();
|
|
41496
41765
|
init_check_module_unlocked();
|
|
41766
|
+
init_courses_filter();
|
|
41497
41767
|
init_date_helpers();
|
|
41498
41768
|
init_lessons();
|
|
41499
41769
|
init_mentorship_services();
|
|
@@ -41791,6 +42061,11 @@ async function runStart(opts, deps = defaultDeps3) {
|
|
|
41791
42061
|
process.stderr.write("Acesse tostudy.ai para estudar este curso pelo ChatStudy.\n");
|
|
41792
42062
|
process.exit(1);
|
|
41793
42063
|
}
|
|
42064
|
+
if (err instanceof CliApiError && err.status === 403 && err.message === "COURSE_ARCHIVED") {
|
|
42065
|
+
process.stderr.write("Este curso foi arquivado e est\xE1 dispon\xEDvel somente para leitura.\n");
|
|
42066
|
+
process.stderr.write("Use `tostudy lesson` para revisar o conte\xFAdo j\xE1 estudado.\n");
|
|
42067
|
+
process.exit(1);
|
|
42068
|
+
}
|
|
41794
42069
|
const msg = err instanceof Error ? err.message : String(err);
|
|
41795
42070
|
deps.error(msg);
|
|
41796
42071
|
}
|
|
@@ -41869,6 +42144,11 @@ var init_start_next = __esm({
|
|
|
41869
42144
|
process.stderr.write("\u2192 tostudy courses para ver outros cursos\n");
|
|
41870
42145
|
process.exit(0);
|
|
41871
42146
|
}
|
|
42147
|
+
if (err instanceof CliApiError && err.status === 403 && err.message === "COURSE_ARCHIVED") {
|
|
42148
|
+
process.stderr.write("Este curso foi arquivado e est\xE1 dispon\xEDvel somente para leitura.\n");
|
|
42149
|
+
process.stderr.write("Use `tostudy lesson` para revisar o conte\xFAdo j\xE1 estudado.\n");
|
|
42150
|
+
process.exit(1);
|
|
42151
|
+
}
|
|
41872
42152
|
const msg = err instanceof Error ? err.message : String(err);
|
|
41873
42153
|
if (opts.json) jsonError(msg);
|
|
41874
42154
|
error(msg);
|
|
@@ -41996,6 +42276,7 @@ var init_lesson = __esm({
|
|
|
41996
42276
|
init_course_state();
|
|
41997
42277
|
init_formatter();
|
|
41998
42278
|
init_resolve();
|
|
42279
|
+
init_errors();
|
|
41999
42280
|
logger12 = createLogger("cli:lesson");
|
|
42000
42281
|
lessonCommand = new Command11("lesson").description("Show the content of the current lesson").option("--json", "Output structured JSON").action(async (opts) => {
|
|
42001
42282
|
try {
|
|
@@ -42029,6 +42310,12 @@ var init_lesson = __esm({
|
|
|
42029
42310
|
}
|
|
42030
42311
|
}
|
|
42031
42312
|
} catch (err) {
|
|
42313
|
+
if (isInsufficientCreditsError(err)) {
|
|
42314
|
+
const friendly = getErrors().insufficientCredits;
|
|
42315
|
+
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
42316
|
+
error(friendly);
|
|
42317
|
+
return;
|
|
42318
|
+
}
|
|
42032
42319
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42033
42320
|
if (opts.json) jsonError(msg);
|
|
42034
42321
|
error(msg);
|
|
@@ -42049,6 +42336,7 @@ var init_hint = __esm({
|
|
|
42049
42336
|
init_guards();
|
|
42050
42337
|
init_course_state();
|
|
42051
42338
|
init_formatter();
|
|
42339
|
+
init_errors();
|
|
42052
42340
|
logger13 = createLogger("cli:hint");
|
|
42053
42341
|
hintCommand = new Command12("hint").description("Get a progressive hint for the current exercise").option("--json", "Output structured JSON").action(async (opts) => {
|
|
42054
42342
|
try {
|
|
@@ -42068,6 +42356,12 @@ var init_hint = __esm({
|
|
|
42068
42356
|
output(formatHint(hint), { json: false });
|
|
42069
42357
|
}
|
|
42070
42358
|
} catch (err) {
|
|
42359
|
+
if (isInsufficientCreditsError(err)) {
|
|
42360
|
+
const friendly = getErrors().insufficientCredits;
|
|
42361
|
+
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
42362
|
+
error(friendly);
|
|
42363
|
+
return;
|
|
42364
|
+
}
|
|
42071
42365
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42072
42366
|
if (opts.json) jsonError(msg);
|
|
42073
42367
|
error(msg);
|
|
@@ -42404,6 +42698,7 @@ var init_validate = __esm({
|
|
|
42404
42698
|
init_course_state();
|
|
42405
42699
|
init_formatter();
|
|
42406
42700
|
init_init_template();
|
|
42701
|
+
init_errors();
|
|
42407
42702
|
logger14 = createLogger("cli:validate");
|
|
42408
42703
|
validateCommand = new Command13("validate").description("Validate your solution for the current exercise").argument("[file]", "Path to the solution file to read").option("--stdin", "Read solution from stdin instead of a file").option("--json", "Output structured JSON").action(async (file2, opts) => {
|
|
42409
42704
|
try {
|
|
@@ -42485,6 +42780,12 @@ var init_validate = __esm({
|
|
|
42485
42780
|
}
|
|
42486
42781
|
process.exit(result.passed ? 0 : 1);
|
|
42487
42782
|
} catch (err) {
|
|
42783
|
+
if (isInsufficientCreditsError(err)) {
|
|
42784
|
+
const friendly = getErrors().insufficientCredits;
|
|
42785
|
+
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
42786
|
+
error(friendly);
|
|
42787
|
+
return;
|
|
42788
|
+
}
|
|
42488
42789
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42489
42790
|
if (opts.json) jsonError(msg);
|
|
42490
42791
|
error(msg);
|
|
@@ -44286,6 +44587,7 @@ var init_theory = __esm({
|
|
|
44286
44587
|
init_src();
|
|
44287
44588
|
init_guards();
|
|
44288
44589
|
init_formatter();
|
|
44590
|
+
init_errors();
|
|
44289
44591
|
logger27 = createLogger("cli:theory");
|
|
44290
44592
|
EXERCISE_LEVELS2 = ["L0", "L1", "L2", "L3", "L4"];
|
|
44291
44593
|
theoryCommand = new Command28("theory").description("Request more theory on the current lesson (escape hatch)").option("--focus <text>", "Optional focus area in PT-BR (max 500 chars)").option("--level <L0|L1|L2|L3|L4>", "Override current exercise level (otherwise auto-detect)").option("--lesson <uuid>", "Override lesson ID (defaults to current workspace lesson)").option("--json", "Output structured JSON").action(async (opts) => {
|
|
@@ -44352,6 +44654,12 @@ var init_theory = __esm({
|
|
|
44352
44654
|
output(formatMoreTheory(data), { json: false });
|
|
44353
44655
|
}
|
|
44354
44656
|
} catch (err) {
|
|
44657
|
+
if (isInsufficientCreditsError(err)) {
|
|
44658
|
+
const friendly = getErrors().insufficientCredits;
|
|
44659
|
+
if (opts.json) jsonError("insufficient_credits", { message: friendly });
|
|
44660
|
+
error(friendly);
|
|
44661
|
+
return;
|
|
44662
|
+
}
|
|
44355
44663
|
const msg = err instanceof Error ? err.message : String(err);
|
|
44356
44664
|
if (opts.json) jsonError("unexpected_error", { message: msg });
|
|
44357
44665
|
error(msg);
|