@learnpack/learnpack 5.0.355 → 5.0.357

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.
Files changed (120) hide show
  1. package/lib/commands/serve.d.ts +0 -17
  2. package/lib/commands/serve.js +159 -129
  3. package/lib/creatorDist/assets/{index-DnthLsvb.js → index-D6pmbMe9.js} +14030 -13903
  4. package/lib/creatorDist/assets/index-zrPponAn.css +1701 -0
  5. package/lib/creatorDist/index.html +2 -2
  6. package/lib/models/creator.d.ts +1 -1
  7. package/lib/services/ingest/adapters/gcsCourseStorage.d.ts +13 -0
  8. package/lib/services/ingest/adapters/gcsCourseStorage.js +58 -0
  9. package/lib/services/ingest/adapters/rigoUserTokenAuth.d.ts +15 -0
  10. package/lib/services/ingest/adapters/rigoUserTokenAuth.js +46 -0
  11. package/lib/services/ingest/adapters/rigobotPackageRegistry.d.ts +7 -0
  12. package/lib/services/ingest/adapters/rigobotPackageRegistry.js +119 -0
  13. package/lib/services/ingest/core/buildIngestConfig.d.ts +27 -0
  14. package/lib/services/ingest/core/buildIngestConfig.js +40 -0
  15. package/lib/services/ingest/core/buildInitialSyllabus.d.ts +24 -0
  16. package/lib/services/ingest/core/buildInitialSyllabus.js +104 -0
  17. package/lib/services/ingest/core/buildSidebar.d.ts +13 -0
  18. package/lib/services/ingest/core/buildSidebar.js +28 -0
  19. package/lib/services/ingest/core/coursePaths.d.ts +31 -0
  20. package/lib/services/ingest/core/coursePaths.js +50 -0
  21. package/lib/services/ingest/core/ingestCoursePackage.d.ts +52 -0
  22. package/lib/services/ingest/core/ingestCoursePackage.js +217 -0
  23. package/lib/services/ingest/core/normalizeLearnJson.d.ts +25 -0
  24. package/lib/services/ingest/core/normalizeLearnJson.js +29 -0
  25. package/lib/services/ingest/core/pairLessons.d.ts +29 -0
  26. package/lib/services/ingest/core/pairLessons.js +102 -0
  27. package/lib/services/ingest/core/planWrites.d.ts +44 -0
  28. package/lib/services/ingest/core/planWrites.js +59 -0
  29. package/lib/services/ingest/core/resolveSlug.d.ts +53 -0
  30. package/lib/services/ingest/core/resolveSlug.js +93 -0
  31. package/lib/services/ingest/core/types.d.ts +53 -0
  32. package/lib/services/ingest/core/types.js +2 -0
  33. package/lib/services/ingest/core/validatePackage.d.ts +38 -0
  34. package/lib/services/ingest/core/validatePackage.js +97 -0
  35. package/lib/services/ingest/createIngestService.d.ts +34 -0
  36. package/lib/services/ingest/createIngestService.js +38 -0
  37. package/lib/services/ingest/errors.d.ts +22 -0
  38. package/lib/services/ingest/errors.js +34 -0
  39. package/lib/services/ingest/http/errorMapping.d.ts +8 -0
  40. package/lib/services/ingest/http/errorMapping.js +40 -0
  41. package/lib/services/ingest/http/router.d.ts +32 -0
  42. package/lib/services/ingest/http/router.js +124 -0
  43. package/lib/services/ingest/http/zipPackageReader.d.ts +26 -0
  44. package/lib/services/ingest/http/zipPackageReader.js +62 -0
  45. package/lib/services/ingest/ports/courseStorage.d.ts +25 -0
  46. package/lib/services/ingest/ports/courseStorage.js +2 -0
  47. package/lib/services/ingest/ports/packageRegistry.d.ts +58 -0
  48. package/lib/services/ingest/ports/packageRegistry.js +2 -0
  49. package/lib/services/ingest/ports/requestAuthenticator.d.ts +25 -0
  50. package/lib/services/ingest/ports/requestAuthenticator.js +2 -0
  51. package/lib/utils/coursePackage/bucketIo.d.ts +23 -0
  52. package/lib/utils/coursePackage/bucketIo.js +36 -0
  53. package/lib/utils/coursePackage/learnJson.d.ts +26 -0
  54. package/lib/utils/coursePackage/learnJson.js +36 -0
  55. package/lib/utils/coursePackage/sidebar.d.ts +15 -0
  56. package/lib/utils/coursePackage/sidebar.js +26 -0
  57. package/lib/utils/creatorSocket.js +15 -21
  58. package/lib/utils/gcpCredentials.d.ts +18 -0
  59. package/lib/utils/gcpCredentials.js +27 -0
  60. package/lib/utils/rigoActions.d.ts +16 -0
  61. package/lib/utils/rigoActions.js +102 -1
  62. package/lib/utils/socketRegistry.d.ts +46 -0
  63. package/lib/utils/socketRegistry.js +83 -0
  64. package/package.json +1 -1
  65. package/src/commands/serve.ts +162 -114
  66. package/src/creator/README.md +63 -51
  67. package/src/creator/package-lock.json +1188 -8
  68. package/src/creator/package.json +5 -1
  69. package/src/creator/src/App.tsx +120 -54
  70. package/src/creator/src/components/FileUploader.tsx +1 -12
  71. package/src/creator/src/components/NotificationListener.tsx +1 -8
  72. package/src/creator/src/components/syllabus/SyllabusEditor.tsx +101 -36
  73. package/src/creator/src/locales/en.json +8 -0
  74. package/src/creator/src/locales/es.json +8 -0
  75. package/src/creator/src/utils/completionResult.test.ts +144 -0
  76. package/src/creator/src/utils/completionResult.ts +154 -0
  77. package/src/creator/src/utils/constants.ts +17 -4
  78. package/src/creator/src/utils/socket.test.ts +113 -0
  79. package/src/creator/src/utils/socket.ts +60 -37
  80. package/src/creator/src/utils/store.ts +84 -67
  81. package/src/creator/src/utils/useCompletionWatchdog.test.ts +99 -0
  82. package/src/creator/src/utils/useCompletionWatchdog.ts +37 -0
  83. package/src/creator/vitest.config.ts +16 -0
  84. package/src/creatorDist/assets/{index-DnthLsvb.js → index-D6pmbMe9.js} +14030 -13903
  85. package/src/creatorDist/assets/index-zrPponAn.css +1701 -0
  86. package/src/creatorDist/index.html +2 -2
  87. package/src/models/creator.ts +1 -1
  88. package/src/services/ingest/adapters/gcsCourseStorage.ts +70 -0
  89. package/src/services/ingest/adapters/rigoUserTokenAuth.ts +65 -0
  90. package/src/services/ingest/adapters/rigobotPackageRegistry.ts +161 -0
  91. package/src/services/ingest/core/buildIngestConfig.ts +51 -0
  92. package/src/services/ingest/core/buildInitialSyllabus.ts +122 -0
  93. package/src/services/ingest/core/buildSidebar.ts +32 -0
  94. package/src/services/ingest/core/coursePaths.ts +59 -0
  95. package/src/services/ingest/core/ingestCoursePackage.ts +343 -0
  96. package/src/services/ingest/core/normalizeLearnJson.ts +47 -0
  97. package/src/services/ingest/core/pairLessons.ts +132 -0
  98. package/src/services/ingest/core/planWrites.ts +91 -0
  99. package/src/services/ingest/core/resolveSlug.ts +119 -0
  100. package/src/services/ingest/core/types.ts +57 -0
  101. package/src/services/ingest/core/validatePackage.ts +132 -0
  102. package/src/services/ingest/createIngestService.ts +66 -0
  103. package/src/services/ingest/errors.ts +45 -0
  104. package/src/services/ingest/http/errorMapping.ts +49 -0
  105. package/src/services/ingest/http/router.ts +156 -0
  106. package/src/services/ingest/http/zipPackageReader.ts +81 -0
  107. package/src/services/ingest/ports/courseStorage.ts +25 -0
  108. package/src/services/ingest/ports/packageRegistry.ts +60 -0
  109. package/src/services/ingest/ports/requestAuthenticator.ts +28 -0
  110. package/src/ui/_app/app.js +325 -325
  111. package/src/ui/app.tar.gz +0 -0
  112. package/src/utils/coursePackage/bucketIo.ts +46 -0
  113. package/src/utils/coursePackage/learnJson.ts +37 -0
  114. package/src/utils/coursePackage/sidebar.ts +28 -0
  115. package/src/utils/creatorSocket.ts +16 -22
  116. package/src/utils/gcpCredentials.ts +38 -0
  117. package/src/utils/rigoActions.ts +163 -0
  118. package/src/utils/socketRegistry.ts +85 -0
  119. package/lib/creatorDist/assets/index-CjddKHB_.css +0 -1
  120. package/src/creatorDist/assets/index-CjddKHB_.css +0 -1
@@ -0,0 +1,99 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { renderHook } from "@testing-library/react";
3
+ import { useCompletionWatchdog } from "./useCompletionWatchdog";
4
+
5
+ const TIMEOUT = 1000;
6
+
7
+ describe("useCompletionWatchdog", () => {
8
+ beforeEach(() => {
9
+ vi.useFakeTimers();
10
+ });
11
+
12
+ afterEach(() => {
13
+ vi.useRealTimers();
14
+ });
15
+
16
+ it("fires once the wait exceeds the timeout", () => {
17
+ const onTimeout = vi.fn();
18
+ renderHook(() => useCompletionWatchdog("abc123", onTimeout, TIMEOUT));
19
+
20
+ expect(onTimeout).not.toHaveBeenCalled();
21
+ vi.advanceTimersByTime(TIMEOUT);
22
+ expect(onTimeout).toHaveBeenCalledTimes(1);
23
+ });
24
+
25
+ it("does not fire more than once", () => {
26
+ const onTimeout = vi.fn();
27
+ renderHook(() => useCompletionWatchdog("abc123", onTimeout, TIMEOUT));
28
+
29
+ vi.advanceTimersByTime(TIMEOUT * 5);
30
+ expect(onTimeout).toHaveBeenCalledTimes(1);
31
+ });
32
+
33
+ it("stays idle while there is no notification to wait for", () => {
34
+ const onTimeout = vi.fn();
35
+ renderHook(() => useCompletionWatchdog("", onTimeout, TIMEOUT));
36
+
37
+ vi.advanceTimersByTime(TIMEOUT * 5);
38
+ expect(onTimeout).not.toHaveBeenCalled();
39
+ });
40
+
41
+ it("cancels when the notification resolves and the id is cleared", () => {
42
+ const onTimeout = vi.fn();
43
+ const { rerender } = renderHook(
44
+ ({ id }) => useCompletionWatchdog(id, onTimeout, TIMEOUT),
45
+ { initialProps: { id: "abc123" } }
46
+ );
47
+
48
+ vi.advanceTimersByTime(TIMEOUT / 2);
49
+ rerender({ id: "" });
50
+ vi.advanceTimersByTime(TIMEOUT * 5);
51
+
52
+ expect(onTimeout).not.toHaveBeenCalled();
53
+ });
54
+
55
+ it("cancels on unmount", () => {
56
+ const onTimeout = vi.fn();
57
+ const { unmount } = renderHook(() =>
58
+ useCompletionWatchdog("abc123", onTimeout, TIMEOUT)
59
+ );
60
+
61
+ unmount();
62
+ vi.advanceTimersByTime(TIMEOUT * 5);
63
+
64
+ expect(onTimeout).not.toHaveBeenCalled();
65
+ });
66
+
67
+ it("restarts the countdown for a new notification", () => {
68
+ const onTimeout = vi.fn();
69
+ const { rerender } = renderHook(
70
+ ({ id }) => useCompletionWatchdog(id, onTimeout, TIMEOUT),
71
+ { initialProps: { id: "first" } }
72
+ );
73
+
74
+ vi.advanceTimersByTime(TIMEOUT * 0.9);
75
+ rerender({ id: "second" });
76
+ vi.advanceTimersByTime(TIMEOUT * 0.9);
77
+
78
+ expect(onTimeout).not.toHaveBeenCalled();
79
+
80
+ vi.advanceTimersByTime(TIMEOUT * 0.2);
81
+ expect(onTimeout).toHaveBeenCalledTimes(1);
82
+ });
83
+
84
+ it("calls the latest callback, so an inline closure does not reset the timer", () => {
85
+ const first = vi.fn();
86
+ const second = vi.fn();
87
+ const { rerender } = renderHook(
88
+ ({ cb }) => useCompletionWatchdog("abc123", cb, TIMEOUT),
89
+ { initialProps: { cb: first } }
90
+ );
91
+
92
+ vi.advanceTimersByTime(TIMEOUT * 0.9);
93
+ rerender({ cb: second });
94
+ vi.advanceTimersByTime(TIMEOUT * 0.2);
95
+
96
+ expect(first).not.toHaveBeenCalled();
97
+ expect(second).toHaveBeenCalledTimes(1);
98
+ });
99
+ });
@@ -0,0 +1,37 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { COMPLETION_TIMEOUT_MS } from "./constants";
3
+
4
+ /**
5
+ * Gives up waiting for a completion notification that never arrives.
6
+ *
7
+ * The socket is the only thing that ends the loading state, so anything that
8
+ * stops the notification from reaching us — a dropped connection, a webhook
9
+ * Rigobot never sent, a relay that gave up retrying — used to leave the UI
10
+ * spinning with no way out. This puts a ceiling on the wait.
11
+ *
12
+ * The callback is held in a ref so that passing an inline closure, which every
13
+ * caller does, does not restart the timer on each render.
14
+ * @param notificationId - The notification being waited on; empty means idle.
15
+ * @param onTimeout - Called once if the wait exceeds `timeoutMs`.
16
+ * @param timeoutMs - How long to wait before giving up.
17
+ */
18
+ export function useCompletionWatchdog(
19
+ notificationId: string,
20
+ onTimeout: () => void,
21
+ timeoutMs: number = COMPLETION_TIMEOUT_MS
22
+ ) {
23
+ const onTimeoutRef = useRef(onTimeout);
24
+ onTimeoutRef.current = onTimeout;
25
+
26
+ useEffect(() => {
27
+ if (!notificationId) return;
28
+
29
+ const timer = setTimeout(() => {
30
+ onTimeoutRef.current();
31
+ }, timeoutMs);
32
+
33
+ return () => {
34
+ clearTimeout(timer);
35
+ };
36
+ }, [notificationId, timeoutMs]);
37
+ }
@@ -0,0 +1,16 @@
1
+ import { defineConfig, mergeConfig } from "vitest/config";
2
+ import viteConfig from "./vite.config";
3
+
4
+ // Kept separate from vite.config.ts so the production build has no dependency on
5
+ // vitest. Merging means the aliases and plugins the app already relies on apply
6
+ // to tests too, with nothing restated here.
7
+ export default mergeConfig(
8
+ viteConfig,
9
+ defineConfig({
10
+ test: {
11
+ // Needed by renderHook; the pure tests do not care either way.
12
+ environment: "jsdom",
13
+ include: ["src/**/*.test.ts", "src/**/*.test.tsx"],
14
+ },
15
+ })
16
+ );