@jant/core 0.3.45 → 0.3.46

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ as url_exports } from "./url-umUptr5z.js";
2
- import { A as SORT_ORDERS, C as toPostViews, D as MAX_PINNED_POSTS, E as MAX_MEDIA_ATTACHMENTS, M as TEXT_ATTACHMENT_CONTENT_FORMATS, O as MEDIA_KINDS, S as toPostView, T as FORMATS, _ as toArchiveGroups, b as toNavItemView, d as defaultFeedRenderer, g as createMediaContext, j as STATUSES, k as NAV_ITEM_TYPES, t as createApp, v as toArchiveGroupsWithMedia, w as toSearchResultView, x as toNavItemViews, y as toMediaView } from "./app-C-L7wL6o.js";
2
+ import { A as SORT_ORDERS, C as toPostViews, D as MAX_PINNED_POSTS, E as MAX_MEDIA_ATTACHMENTS, M as TEXT_ATTACHMENT_CONTENT_FORMATS, O as MEDIA_KINDS, S as toPostView, T as FORMATS, _ as toArchiveGroups, b as toNavItemView, d as defaultFeedRenderer, g as createMediaContext, j as STATUSES, k as NAV_ITEM_TYPES, t as createApp, v as toArchiveGroupsWithMedia, w as toSearchResultView, x as toNavItemViews, y as toMediaView } from "./app-DB-P66E5.js";
3
3
  import { E as time_exports, s as markdown_exports } from "./github-sync-CQ1x271f.js";
4
4
  import "./env-CgaH9Mut.js";
5
5
  export { FORMATS, MAX_MEDIA_ATTACHMENTS, MAX_PINNED_POSTS, MEDIA_KINDS, NAV_ITEM_TYPES, SORT_ORDERS, STATUSES, TEXT_ATTACHMENT_CONTENT_FORMATS, createApp, createMediaContext, defaultFeedRenderer, markdown_exports as markdown, time_exports as time, toArchiveGroups, toArchiveGroupsWithMedia, toMediaView, toNavItemView, toNavItemViews, toPostView, toPostViews, toSearchResultView, url_exports as url };
package/dist/node.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./url-umUptr5z.js";
2
- import { F as getPublicAssetBasePath, I as isAssetPath, N as buildThemeStyle, P as BUILTIN_COLOR_THEMES, a as resolveDatabaseDialect, c as BUILTIN_FONT_THEMES, f as pgSchemaBundle, h as schema_exports, i as createSiteService, l as getCjkSerifCssVariables, m as createNodeDatabase, n as createNodeCliRuntime, o as getHostBasedStartupConfigurationIssues, p as sqliteSchemaBundle, r as createNodeRequestRuntime, s as resolveConfig, t as createApp, u as getFontThemeCssVariables } from "./app-C-L7wL6o.js";
2
+ import { F as getPublicAssetBasePath, I as isAssetPath, N as buildThemeStyle, P as BUILTIN_COLOR_THEMES, a as resolveDatabaseDialect, c as BUILTIN_FONT_THEMES, f as pgSchemaBundle, h as schema_exports, i as createSiteService, l as getCjkSerifCssVariables, m as createNodeDatabase, n as createNodeCliRuntime, o as getHostBasedStartupConfigurationIssues, p as sqliteSchemaBundle, r as createNodeRequestRuntime, s as resolveConfig, t as createApp, u as getFontThemeCssVariables } from "./app-DB-P66E5.js";
3
3
  import { i as createExportService } from "./github-sync-CQ1x271f.js";
4
4
  import { b as getSiteResolutionMode, i as getConfiguredSingleSitePathPrefix, l as getEnvString, r as getConfiguredSingleSiteOrigin, x as shouldTrustProxy, y as getPort } from "./env-CgaH9Mut.js";
5
5
  import { drizzle } from "drizzle-orm/better-sqlite3";
@@ -473,7 +473,7 @@ async function createNodeRequestHandler(options) {
473
473
  async function start(env = process.env, app) {
474
474
  const handler = await createNodeRequestHandler({
475
475
  env,
476
- app: async () => app ?? (await import("./app-Hvqe7Ks_.js")).createApp()
476
+ app: async () => app ?? (await import("./app-CM7sb3xO.js")).createApp()
477
477
  });
478
478
  const hostname = resolveHost(env);
479
479
  const port = resolvePort(env);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jant/core",
3
- "version": "0.3.45",
3
+ "version": "0.3.46",
4
4
  "description": "A modern, open-source microblogging platform built on Cloudflare Workers",
5
5
  "type": "module",
6
6
  "exports": {
@@ -23,6 +23,7 @@ const {
23
23
  getRootAliasPathsForImport,
24
24
  uploadMediaList,
25
25
  normalizeTextAttachmentSpec,
26
+ isAbsoluteImportUrl,
26
27
  } = __test__;
27
28
 
28
29
  async function writeFileTree(
@@ -226,6 +227,23 @@ describe("Hugo import CLI helpers", () => {
226
227
  );
227
228
  });
228
229
 
230
+ it("isAbsoluteImportUrl distinguishes absolute URLs from relative paths for --skip-remote-media", () => {
231
+ // Relative paths — always treated as the source site's own files.
232
+ expect(isAbsoluteImportUrl("/media/foo.png")).toBe(false);
233
+ expect(isAbsoluteImportUrl("./foo.png")).toBe(false);
234
+ expect(isAbsoluteImportUrl("../foo.png")).toBe(false);
235
+ expect(isAbsoluteImportUrl("foo.png")).toBe(false);
236
+ // Absolute / scheme'd / protocol-relative URLs — treated as remote.
237
+ expect(isAbsoluteImportUrl("https://example.com/foo.png")).toBe(true);
238
+ expect(isAbsoluteImportUrl("http://example.com/foo.png")).toBe(true);
239
+ expect(isAbsoluteImportUrl("HTTPS://Example.com/Foo.png")).toBe(true);
240
+ expect(isAbsoluteImportUrl("//cdn.example.com/foo.png")).toBe(true);
241
+ expect(isAbsoluteImportUrl("data:image/png;base64,AAA")).toBe(true);
242
+ // Non-strings.
243
+ expect(isAbsoluteImportUrl(undefined)).toBe(false);
244
+ expect(isAbsoluteImportUrl(null)).toBe(false);
245
+ });
246
+
229
247
  it("normalizeTextAttachmentSpec handles a kind:text entry from front matter media[]", async () => {
230
248
  await mkdir(join(tempDir, "static", "media", "files"), { recursive: true });
231
249
  await writeFile(
@@ -40,6 +40,7 @@ import { getMediaCategory } from "../../lib/upload.js";
40
40
  import { getSlugValidationIssue } from "../../lib/slug-format.js";
41
41
  import { createTiptapEditor } from "../tiptap/create-editor.js";
42
42
  import { MAX_THREAD_POSTS } from "../../types.js";
43
+ import { randomUUID } from "../random-uuid.js";
43
44
 
44
45
  interface ReplyToMedia {
45
46
  url: string;
@@ -2788,9 +2789,9 @@ export class JantComposeDialog extends LitElement {
2788
2789
 
2789
2790
  // Enter thread mode
2790
2791
  this._threadItems = [
2791
- { id: crypto.randomUUID(), format: post.format },
2792
+ { id: randomUUID(), format: post.format },
2792
2793
  ...ordered.map((p) => ({
2793
- id: crypto.randomUUID(),
2794
+ id: randomUUID(),
2794
2795
  format: p.format,
2795
2796
  })),
2796
2797
  ];
@@ -3161,7 +3162,7 @@ export class JantComposeDialog extends LitElement {
3161
3162
  if (draft.threadItems && draft.threadItems.length >= 2) {
3162
3163
  this._format = draft.threadItems[0].format;
3163
3164
  this._threadItems = draft.threadItems.map((item) => ({
3164
- id: crypto.randomUUID(),
3165
+ id: randomUUID(),
3165
3166
  format: item.format,
3166
3167
  }));
3167
3168
  this._focusedThreadIndex = 0;
@@ -5097,8 +5098,8 @@ export class JantComposeDialog extends LitElement {
5097
5098
  const bodyJson = currentEditor?.getNormalizedBodyJson() ?? null;
5098
5099
 
5099
5100
  this._threadItems = [
5100
- { id: crypto.randomUUID(), format: this._format },
5101
- { id: crypto.randomUUID(), format: lastFormat },
5101
+ { id: randomUUID(), format: this._format },
5102
+ { id: randomUUID(), format: lastFormat },
5102
5103
  ];
5103
5104
 
5104
5105
  // Capture rating state before re-render (these can't change asynchronously)
@@ -5157,7 +5158,7 @@ export class JantComposeDialog extends LitElement {
5157
5158
  } else {
5158
5159
  this._threadItems = [
5159
5160
  ...this._threadItems,
5160
- { id: crypto.randomUUID(), format: lastFormat },
5161
+ { id: randomUUID(), format: lastFormat },
5161
5162
  ];
5162
5163
  }
5163
5164
 
@@ -47,6 +47,7 @@ import {
47
47
  adoptPendingInlineImageUploads,
48
48
  } from "../tiptap/inline-image-upload.js";
49
49
  import { isSafeAbsoluteUrl } from "../../lib/url.js";
50
+ import { randomUUID } from "../random-uuid.js";
50
51
 
51
52
  interface ComposeFilePickerCloseDetail {
52
53
  cancelled: boolean;
@@ -220,7 +221,7 @@ export class JantComposeEditor extends LitElement {
220
221
  private _lastEditorSelection: ComposeEditorSelection | null = null;
221
222
  private _emojiPickerEl: HTMLElement | null = null;
222
223
  private _emojiContainer: HTMLElement | null = null;
223
- private readonly _urlStatusId = `compose-url-status-${crypto.randomUUID()}`;
224
+ private readonly _urlStatusId = `compose-url-status-${randomUUID()}`;
224
225
  private _onDocClickBound = this._onDocumentClick.bind(this);
225
226
  private _scrollBufferApplied = false;
226
227
  private _filePickerCleanup: (() => void) | null = null;
@@ -880,7 +881,7 @@ export class JantComposeEditor extends LitElement {
880
881
  // Convert media attachments to ComposeAttachment[] with status "done"
881
882
  if (data.media?.length) {
882
883
  const attachments = data.media.map((m) => ({
883
- clientId: crypto.randomUUID(),
884
+ clientId: randomUUID(),
884
885
  file: new File([], m.originalName ?? "existing", { type: m.mimeType }),
885
886
  previewUrl: m.previewUrl,
886
887
  posterUrl: null,
@@ -906,7 +907,7 @@ export class JantComposeEditor extends LitElement {
906
907
  // Invalid JSON — leave as null
907
908
  }
908
909
  return {
909
- clientId: t.clientId ?? crypto.randomUUID(),
910
+ clientId: t.clientId ?? randomUUID(),
910
911
  bodyJson: parsed,
911
912
  bodyHtml: t.bodyHtml ?? "",
912
913
  summary: t.summary,
@@ -979,7 +980,7 @@ export class JantComposeEditor extends LitElement {
979
980
 
980
981
  private _openAttachedText() {
981
982
  const item: AttachedTextItem = {
982
- clientId: crypto.randomUUID(),
983
+ clientId: randomUUID(),
983
984
  bodyJson: null,
984
985
  bodyHtml: "",
985
986
  summary: "",
@@ -1242,7 +1243,7 @@ export class JantComposeEditor extends LitElement {
1242
1243
  continue;
1243
1244
  }
1244
1245
 
1245
- const clientId = crypto.randomUUID();
1246
+ const clientId = randomUUID();
1246
1247
  const previewUrl = URL.createObjectURL(file);
1247
1248
  newAttachments.push({
1248
1249
  clientId,
@@ -0,0 +1,23 @@
1
+ /**
2
+ * RFC4122 v4 UUID generator with fallback for insecure contexts.
3
+ *
4
+ * `crypto.randomUUID()` is only available in secure contexts (HTTPS or
5
+ * localhost). Self-hosted Jant deployments are often accessed over plain
6
+ * HTTP on a LAN address, where the native API is `undefined`. This helper
7
+ * uses the native API when available and falls back to a `Math.random`-based
8
+ * v4 string otherwise. The fallback is not cryptographically strong, but
9
+ * client-side IDs here only need to be unique within a single page session.
10
+ */
11
+ export const randomUUID = (): string => {
12
+ if (
13
+ typeof crypto !== "undefined" &&
14
+ typeof crypto.randomUUID === "function"
15
+ ) {
16
+ return crypto.randomUUID();
17
+ }
18
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
19
+ const r = (Math.random() * 16) | 0;
20
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
21
+ return v.toString(16);
22
+ });
23
+ };
@@ -49,10 +49,7 @@ export const HomePage: FC<HomePageProps> = ({
49
49
  {!isAuthenticated && (
50
50
  <>
51
51
  {" "}
52
- <a
53
- href={signinUrl}
54
- class="underline-offset-2 hover:underline"
55
- >
52
+ <a href={signinUrl} class="underline underline-offset-2">
56
53
  {i18n._(
57
54
  msg({
58
55
  message: "Sign in if this is your space.",