jamdesk 1.1.203 → 1.1.205

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 (112) hide show
  1. package/dist/__tests__/integration/fix-scan-integration.test.js.map +1 -1
  2. package/dist/__tests__/integration/init.integration.test.js.map +1 -1
  3. package/dist/__tests__/integration/prepublish.integration.test.js.map +1 -1
  4. package/dist/__tests__/integration/validate.integration.test.js.map +1 -1
  5. package/dist/__tests__/unit/banner-art-sync.test.js.map +1 -1
  6. package/dist/__tests__/unit/deploy-templates.test.js.map +1 -1
  7. package/dist/__tests__/unit/deploy.test.js +106 -0
  8. package/dist/__tests__/unit/deploy.test.js.map +1 -1
  9. package/dist/__tests__/unit/deprecated-components-sync.test.js.map +1 -1
  10. package/dist/__tests__/unit/deps-sync.test.js.map +1 -1
  11. package/dist/__tests__/unit/dev-spinner-ownership.test.js.map +1 -1
  12. package/dist/__tests__/unit/docs-config.test.js.map +1 -1
  13. package/dist/__tests__/unit/fix-engine-sync.test.js.map +1 -1
  14. package/dist/__tests__/unit/frontmatter-sync.test.js.map +1 -1
  15. package/dist/__tests__/unit/heading-extractor-sync.test.js.map +1 -1
  16. package/dist/__tests__/unit/inert-config-keys-sync.test.js.map +1 -1
  17. package/dist/__tests__/unit/init.test.js.map +1 -1
  18. package/dist/__tests__/unit/install-banner-gating.test.js.map +1 -1
  19. package/dist/__tests__/unit/jwt-auth-config-drift.test.d.ts +22 -0
  20. package/dist/__tests__/unit/jwt-auth-config-drift.test.d.ts.map +1 -0
  21. package/dist/__tests__/unit/jwt-auth-config-drift.test.js +193 -0
  22. package/dist/__tests__/unit/jwt-auth-config-drift.test.js.map +1 -0
  23. package/dist/__tests__/unit/openapi-schema-patch-sync.test.js.map +1 -1
  24. package/dist/__tests__/unit/openapi-schema-runtime-patch.test.js +1 -1
  25. package/dist/__tests__/unit/openapi.test.js.map +1 -1
  26. package/dist/__tests__/unit/package-config.test.js.map +1 -1
  27. package/dist/__tests__/unit/project-favicon.test.js.map +1 -1
  28. package/dist/__tests__/unit/prompt-vendoring.test.js.map +1 -1
  29. package/dist/__tests__/unit/risky-expression-scanner-sync.test.js.map +1 -1
  30. package/dist/__tests__/unit/seo-ai-schema.test.js.map +1 -1
  31. package/dist/__tests__/unit/snippet-scanner-sync.test.js.map +1 -1
  32. package/dist/__tests__/unit/spec-generation-notice.test.js.map +1 -1
  33. package/dist/__tests__/unit/templates-consistency.test.js.map +1 -1
  34. package/dist/__tests__/unit/validate-inert-config-keys.test.js.map +1 -1
  35. package/dist/__tests__/unit/validate-jwt-auth.test.d.ts +2 -0
  36. package/dist/__tests__/unit/validate-jwt-auth.test.d.ts.map +1 -0
  37. package/dist/__tests__/unit/validate-jwt-auth.test.js +77 -0
  38. package/dist/__tests__/unit/validate-jwt-auth.test.js.map +1 -0
  39. package/dist/__tests__/unit/validate-password-warning.test.js.map +1 -1
  40. package/dist/__tests__/unit/vendored-sync.test.js +11 -0
  41. package/dist/__tests__/unit/vendored-sync.test.js.map +1 -1
  42. package/dist/commands/broken-links.js.map +1 -1
  43. package/dist/commands/clean.js.map +1 -1
  44. package/dist/commands/deploy/cloudflare.js.map +1 -1
  45. package/dist/commands/deploy.js +16 -0
  46. package/dist/commands/deploy.js.map +1 -1
  47. package/dist/commands/dev.js.map +1 -1
  48. package/dist/commands/fix.d.ts.map +1 -1
  49. package/dist/commands/fix.js.map +1 -1
  50. package/dist/commands/init.js.map +1 -1
  51. package/dist/commands/update.js.map +1 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/lib/auth.js.map +1 -1
  54. package/dist/lib/deps.d.ts +4 -4
  55. package/dist/lib/deps.d.ts.map +1 -1
  56. package/dist/lib/deps.js +15 -10
  57. package/dist/lib/deps.js.map +1 -1
  58. package/dist/lib/docs-config.d.ts +1 -0
  59. package/dist/lib/docs-config.d.ts.map +1 -1
  60. package/dist/lib/docs-config.js +49 -0
  61. package/dist/lib/docs-config.js.map +1 -1
  62. package/dist/lib/errors.d.ts.map +1 -1
  63. package/dist/lib/errors.js.map +1 -1
  64. package/dist/lib/find-project-dir.js.map +1 -1
  65. package/dist/lib/first-run-banner.js.map +1 -1
  66. package/dist/lib/mdx-validator.js.map +1 -1
  67. package/dist/lib/missing-description-scan.js.map +1 -1
  68. package/dist/utils/update-checker.js.map +1 -1
  69. package/package.json +9 -8
  70. package/vendored/app/(jd-system)/jd-inactive/BrandedInactive.tsx +1 -7
  71. package/vendored/app/(jd-system)/jd-inactive/page.tsx +2 -4
  72. package/vendored/app/(unlock)/jd/auth/callback/CallbackClient.tsx +33 -0
  73. package/vendored/app/(unlock)/jd/auth/callback/page.tsx +15 -0
  74. package/vendored/app/(unlock)/jd/unlock/page.tsx +29 -7
  75. package/vendored/app/api/jd/auth/callback/route.ts +103 -0
  76. package/vendored/app/api/jd/auth/logout/route.ts +38 -0
  77. package/vendored/app/api/jd/auth/me/route.ts +52 -0
  78. package/vendored/app/api/jd/unlock/route.ts +26 -2
  79. package/vendored/app/api/markdown-export/[project]/[...slug]/route.ts +65 -22
  80. package/vendored/app/api/raw-content/[...slug]/route.ts +21 -1
  81. package/vendored/app/layout.tsx +7 -0
  82. package/vendored/components/AIActionsMenu.tsx +19 -2
  83. package/vendored/components/mdx/OpenApiEndpoint.tsx +4 -0
  84. package/vendored/components/navigation/Header.tsx +5 -0
  85. package/vendored/components/navigation/LogoutButton.tsx +41 -0
  86. package/vendored/lib/auth-resolver.ts +125 -50
  87. package/vendored/lib/cached-redis.ts +28 -3
  88. package/vendored/lib/docs-types.ts +17 -1
  89. package/vendored/lib/glob-match.ts +54 -0
  90. package/vendored/lib/jwt-auth-config.ts +37 -0
  91. package/vendored/lib/jwt-session.ts +98 -0
  92. package/vendored/lib/language-utils.ts +14 -2
  93. package/vendored/lib/layout-helpers.tsx +4 -0
  94. package/vendored/lib/mdx-inline-components.ts +1 -1
  95. package/vendored/lib/middleware-helpers.ts +27 -6
  96. package/vendored/lib/nav-group-filter.ts +81 -0
  97. package/vendored/lib/public-paths-resolver.ts +164 -7
  98. package/vendored/lib/r2-public-storage-guard.ts +26 -4
  99. package/vendored/lib/redis.ts +20 -2
  100. package/vendored/lib/render-doc-page.tsx +76 -34
  101. package/vendored/lib/root-page-slug.ts +110 -0
  102. package/vendored/lib/same-origin.ts +38 -0
  103. package/vendored/lib/sanitize-from.ts +31 -1
  104. package/vendored/lib/session-hint.ts +11 -0
  105. package/vendored/lib/snippet-compiler-isr.ts +1 -1
  106. package/vendored/lib/snippet-loader-isr.ts +1 -1
  107. package/vendored/lib/validate-config.ts +14 -0
  108. package/vendored/lib/viewer-navigation.ts +45 -0
  109. package/vendored/lib/visibility.ts +65 -0
  110. package/vendored/schema/docs-schema.json +25 -0
  111. package/vendored/shared/auth-cookie.ts +98 -5
  112. package/vendored/workspace-package-lock.json +474 -183
@@ -15,15 +15,23 @@
15
15
  * which is not available in Edge runtime. This module reimplements a
16
16
  * minimal constant-time compare over Uint8Array outputs from Web Crypto.
17
17
  *
18
- * Cookie wire format:
18
+ * Cookie wire format (v1, password-gated sites — unchanged, byte-for-byte):
19
19
  * base64url(`v1.${version}.${expiresAt}.${base64url(HMAC_SHA256(`v1|${slug}|${host}|${version}|${expiresAt}`, secret))}`)
20
20
  *
21
- * The "v1" prefix on both the HMAC input and the body makes it safe to
22
- * rotate the payload format in the future without silently accepting old
23
- * cookies with a different binding.
21
+ * Cookie wire format (v2, JWT-gated sites — carries signed groups + playground
22
+ * inputs, raw dotted string with NO outer base64 wrap to reclaim cookie budget):
23
+ * `v2.${version}.${expiresAt}.${extrasB64}.${sigB64}`
24
+ * where sigB64 = base64url(HMAC_SHA256(`v2|${slug}|${host}|${version}|${expiresAt}|${extrasB64}`, secret))
25
+ *
26
+ * The "v1"/"v2" prefix on both the HMAC input and the body makes it safe to
27
+ * rotate the payload format without silently accepting a cookie signed under
28
+ * a different binding. verifyAuthCookie() branches on the RAW `v2.` prefix
29
+ * before attempting the v1 base64 decode, so both formats verify correctly
30
+ * from the same function.
24
31
  */
25
32
 
26
33
  const FORMAT_VERSION = 'v1';
34
+ const FORMAT_VERSION_V2 = 'v2';
27
35
 
28
36
  export interface AuthCookiePayload {
29
37
  slug: string;
@@ -38,9 +46,19 @@ export interface VerifyExpectation {
38
46
  version: number;
39
47
  }
40
48
 
49
+ /** Signed extras carried by v2 cookies: JWT-sourced groups + playground inputs. */
50
+ export interface SessionExtras {
51
+ /** User groups from the JWT payload. */
52
+ g?: string[];
53
+ /** apiPlaygroundInputs from the JWT payload (size-capped by the callback route). */
54
+ api?: Record<string, unknown>;
55
+ }
56
+
41
57
  export interface VerifyResult {
42
58
  valid: boolean;
43
59
  expiresAt?: number;
60
+ formatVersion?: 'v1' | 'v2';
61
+ extras?: SessionExtras;
44
62
  }
45
63
 
46
64
  function base64url(bytes: Uint8Array): string {
@@ -102,6 +120,20 @@ function buildSignInput(
102
120
  return `${FORMAT_VERSION}|${slug}|${host}|${version}|${expiresAt}`;
103
121
  }
104
122
 
123
+ function utf8ToBase64url(s: string): string {
124
+ return base64url(new TextEncoder().encode(s));
125
+ }
126
+
127
+ function buildSignInputV2(
128
+ slug: string,
129
+ host: string,
130
+ version: number,
131
+ expiresAt: number,
132
+ extrasB64: string
133
+ ): string {
134
+ return `${FORMAT_VERSION_V2}|${slug}|${host}|${version}|${expiresAt}|${extrasB64}`;
135
+ }
136
+
105
137
  /**
106
138
  * Sign a cookie payload. Returns the full cookie value string to put in Set-Cookie.
107
139
  */
@@ -119,15 +151,44 @@ export async function signAuthCookie(
119
151
  return base64url(new TextEncoder().encode(body));
120
152
  }
121
153
 
154
+ /**
155
+ * Sign a v2 cookie payload carrying signed extras (groups + playground inputs).
156
+ *
157
+ * Wire format: the raw string `v2.${version}.${expiresAt}.${extrasB64}.${sigB64}`
158
+ * — NO outer base64 wrap (every segment is already cookie-safe base64url or
159
+ * digits; v1's whole-body wrap costs ~25% of the ~4KB cookie budget, and v2
160
+ * carries groups in the cookie, so the headroom is load-bearing).
161
+ * extrasB64 = base64url(utf8(JSON.stringify(extras))). The extras segment is
162
+ * inside the HMAC, so groups/playground data can't be forged.
163
+ */
164
+ export async function signAuthCookieV2(
165
+ payload: AuthCookiePayload,
166
+ extras: SessionExtras,
167
+ secret: string
168
+ ): Promise<string> {
169
+ const extrasB64 = utf8ToBase64url(JSON.stringify(extras));
170
+ const sig = await hmac(
171
+ secret,
172
+ buildSignInputV2(payload.slug, payload.host, payload.version, payload.expiresAt, extrasB64)
173
+ );
174
+ return `${FORMAT_VERSION_V2}.${payload.version}.${payload.expiresAt}.${extrasB64}.${base64url(sig)}`;
175
+ }
176
+
122
177
  /**
123
178
  * Verify a cookie value against the expected slug, host, and version.
124
179
  * Returns { valid: false } on any failure (including malformed input).
180
+ * Handles both the legacy v1 (whole-body base64-wrapped) format and the v2
181
+ * (raw dotted, unwrapped) format — identified by the raw `v2.` prefix, which
182
+ * is checked before the v1 base64 decode since v2 is never base64-wrapped.
125
183
  */
126
184
  export async function verifyAuthCookie(
127
185
  cookie: string,
128
186
  expected: VerifyExpectation,
129
187
  secret: string
130
188
  ): Promise<VerifyResult> {
189
+ if (cookie.startsWith(`${FORMAT_VERSION_V2}.`)) {
190
+ return verifyV2(cookie, expected, secret);
191
+ }
131
192
  try {
132
193
  if (!cookie) return { valid: false };
133
194
  const bodyBytes = fromBase64url(cookie);
@@ -156,8 +217,40 @@ export async function verifyAuthCookie(
156
217
  const actualSig = fromBase64url(sigB64);
157
218
  if (!constantTimeEqual(expectedSig, actualSig)) return { valid: false };
158
219
 
159
- return { valid: true, expiresAt };
220
+ return { valid: true, expiresAt, formatVersion: 'v1' };
160
221
  } catch {
161
222
  return { valid: false };
162
223
  }
163
224
  }
225
+
226
+ /**
227
+ * Verify a v2 (raw dotted, unwrapped) cookie. Split out of verifyAuthCookie
228
+ * so the v1 path stays byte-for-byte unchanged for existing password sites.
229
+ */
230
+ async function verifyV2(
231
+ cookie: string,
232
+ expected: VerifyExpectation,
233
+ secret: string
234
+ ): Promise<VerifyResult> {
235
+ const parts = cookie.split('.');
236
+ if (parts.length !== 5) return { valid: false };
237
+ const [, versionStr, expiresAtStr, extrasB64, sigB64] = parts;
238
+ const version = Number(versionStr);
239
+ const expiresAt = Number(expiresAtStr);
240
+ if (!Number.isSafeInteger(version) || !Number.isSafeInteger(expiresAt)) {
241
+ return { valid: false };
242
+ }
243
+ if (version !== expected.version) return { valid: false };
244
+ if (expiresAt <= Date.now()) return { valid: false };
245
+ try {
246
+ const expectedSig = await hmac(
247
+ secret,
248
+ buildSignInputV2(expected.slug, expected.host, version, expiresAt, extrasB64)
249
+ );
250
+ if (!constantTimeEqual(expectedSig, fromBase64url(sigB64))) return { valid: false };
251
+ const extras = JSON.parse(new TextDecoder().decode(fromBase64url(extrasB64))) as SessionExtras;
252
+ return { valid: true, expiresAt, formatVersion: 'v2', extras };
253
+ } catch {
254
+ return { valid: false }; // malformed base64 / JSON — same catch discipline as v1
255
+ }
256
+ }