emdash 0.1.0 → 0.1.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.
Files changed (111) hide show
  1. package/LICENSE +9 -0
  2. package/dist/{apply-Bjfq_b4-.mjs → apply-kC39ev1Z.mjs} +4 -4
  3. package/dist/{apply-Bjfq_b4-.mjs.map → apply-kC39ev1Z.mjs.map} +1 -1
  4. package/dist/astro/index.d.mts +3 -3
  5. package/dist/astro/index.mjs +16 -1
  6. package/dist/astro/index.mjs.map +1 -1
  7. package/dist/astro/middleware/auth.d.mts +3 -3
  8. package/dist/astro/middleware/request-context.mjs +84 -22
  9. package/dist/astro/middleware/request-context.mjs.map +1 -1
  10. package/dist/astro/middleware.mjs +41 -12
  11. package/dist/astro/middleware.mjs.map +1 -1
  12. package/dist/astro/types.d.mts +5 -4
  13. package/dist/astro/types.d.mts.map +1 -1
  14. package/dist/cli/index.mjs +65 -6
  15. package/dist/cli/index.mjs.map +1 -1
  16. package/dist/db/index.mjs +1 -1
  17. package/dist/{index-C1xF3OGh.d.mts → index-CLBc4gw-.d.mts} +42 -11
  18. package/dist/{index-C1xF3OGh.d.mts.map → index-CLBc4gw-.d.mts.map} +1 -1
  19. package/dist/index.d.mts +5 -5
  20. package/dist/index.mjs +9 -9
  21. package/dist/{manifest-schema-Dcl0R6nM.mjs → manifest-schema-CL8DWO9b.mjs} +5 -2
  22. package/dist/manifest-schema-CL8DWO9b.mjs.map +1 -0
  23. package/dist/media/index.d.mts +1 -1
  24. package/dist/media/index.mjs +1 -1
  25. package/dist/media/local-runtime.d.mts +4 -4
  26. package/dist/page/index.d.mts +1 -1
  27. package/dist/{placeholder-CmGAmqeO.d.mts → placeholder-SvFCKbz_.d.mts} +10 -2
  28. package/dist/{placeholder-CmGAmqeO.d.mts.map → placeholder-SvFCKbz_.d.mts.map} +1 -1
  29. package/dist/{placeholder-SmpOx-_v.mjs → placeholder-aiCD8aSZ.mjs} +27 -2
  30. package/dist/placeholder-aiCD8aSZ.mjs.map +1 -0
  31. package/dist/plugins/adapt-sandbox-entry.d.mts +3 -3
  32. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  33. package/dist/{query-CS_iSj34.mjs → query-BVYN0PJ6.mjs} +2 -2
  34. package/dist/{query-CS_iSj34.mjs.map → query-BVYN0PJ6.mjs.map} +1 -1
  35. package/dist/{registry-D_w5HW4G.mjs → registry-BNYQKX_d.mjs} +23 -38
  36. package/dist/registry-BNYQKX_d.mjs.map +1 -0
  37. package/dist/{runner-C0hCbYnD.mjs → runner-BraqvGYk.mjs} +251 -158
  38. package/dist/runner-BraqvGYk.mjs.map +1 -0
  39. package/dist/runner-EAtf0ZIe.d.mts.map +1 -1
  40. package/dist/runtime.d.mts +4 -4
  41. package/dist/{search-DG603UrT.mjs → search-C1gg67nN.mjs} +125 -18
  42. package/dist/search-C1gg67nN.mjs.map +1 -0
  43. package/dist/seed/index.d.mts +1 -1
  44. package/dist/seed/index.mjs +3 -3
  45. package/dist/{types-DvhsUmSJ.d.mts → types-BQo5JS0J.d.mts} +15 -2
  46. package/dist/{types-DvhsUmSJ.d.mts.map → types-BQo5JS0J.d.mts.map} +1 -1
  47. package/dist/{types-DY5zk5HN.mjs → types-CiA5Gac0.mjs} +5 -3
  48. package/dist/types-CiA5Gac0.mjs.map +1 -0
  49. package/dist/{types-C4-fAxN3.d.mts → types-DPfzHnjW.d.mts} +13 -2
  50. package/dist/types-DPfzHnjW.d.mts.map +1 -0
  51. package/dist/{validate-CpBtVMsD.d.mts → validate-HtxZeaBi.d.mts} +2 -2
  52. package/dist/{validate-CpBtVMsD.d.mts.map → validate-HtxZeaBi.d.mts.map} +1 -1
  53. package/dist/{validate-O7PWmlnq.mjs → validate-_rsF-Dx_.mjs} +2 -2
  54. package/dist/{validate-O7PWmlnq.mjs.map → validate-_rsF-Dx_.mjs.map} +1 -1
  55. package/package.json +6 -4
  56. package/src/api/handlers/marketplace.ts +7 -4
  57. package/src/api/schemas/schema.ts +12 -0
  58. package/src/astro/integration/index.ts +17 -0
  59. package/src/astro/integration/runtime.ts +13 -0
  60. package/src/astro/integration/virtual-modules.ts +13 -1
  61. package/src/astro/routes/admin.astro +1 -1
  62. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +3 -1
  63. package/src/astro/routes/api/auth/invite/complete.ts +2 -1
  64. package/src/astro/routes/api/auth/passkey/options.ts +2 -1
  65. package/src/astro/routes/api/auth/passkey/register/options.ts +2 -1
  66. package/src/astro/routes/api/auth/passkey/register/verify.ts +2 -1
  67. package/src/astro/routes/api/auth/passkey/verify.ts +2 -1
  68. package/src/astro/routes/api/auth/signup/complete.ts +2 -1
  69. package/src/astro/routes/api/import/wordpress/analyze.ts +24 -3
  70. package/src/astro/routes/api/import/wordpress/execute.ts +5 -1
  71. package/src/astro/routes/api/import/wordpress/prepare.ts +2 -2
  72. package/src/astro/routes/api/media.ts +16 -4
  73. package/src/astro/routes/api/search/index.ts +1 -5
  74. package/src/astro/routes/api/search/suggest.ts +1 -5
  75. package/src/astro/routes/api/setup/admin-verify.ts +2 -1
  76. package/src/astro/routes/api/setup/admin.ts +2 -1
  77. package/src/astro/types.ts +1 -0
  78. package/src/auth/passkey-config.ts +24 -3
  79. package/src/cli/commands/bundle-utils.ts +26 -0
  80. package/src/cli/commands/bundle.ts +15 -0
  81. package/src/cli/commands/content.ts +11 -1
  82. package/src/cli/commands/login.ts +2 -0
  83. package/src/cli/commands/media.ts +5 -1
  84. package/src/cli/commands/menu.ts +3 -1
  85. package/src/cli/commands/schema.ts +7 -1
  86. package/src/cli/commands/search-cmd.ts +2 -1
  87. package/src/cli/commands/taxonomy.ts +4 -1
  88. package/src/cli/output.ts +14 -0
  89. package/src/components/InlinePortableTextEditor.tsx +33 -3
  90. package/src/database/migrations/033_optimize_content_indexes.ts +113 -0
  91. package/src/database/migrations/runner.ts +40 -33
  92. package/src/database/repositories/comment.ts +32 -20
  93. package/src/emdash-runtime.ts +64 -2
  94. package/src/media/placeholder.ts +31 -0
  95. package/src/media/thumbnail.ts +32 -0
  96. package/src/plugins/hooks.ts +91 -0
  97. package/src/plugins/manager.ts +22 -0
  98. package/src/plugins/manifest-schema.ts +3 -0
  99. package/src/plugins/marketplace.ts +25 -12
  100. package/src/plugins/types.ts +24 -0
  101. package/src/schema/registry.ts +23 -27
  102. package/src/schema/types.ts +27 -1
  103. package/src/search/fts-manager.ts +1 -18
  104. package/src/visual-editing/toolbar.ts +84 -22
  105. package/dist/manifest-schema-Dcl0R6nM.mjs.map +0 -1
  106. package/dist/placeholder-SmpOx-_v.mjs.map +0 -1
  107. package/dist/registry-D_w5HW4G.mjs.map +0 -1
  108. package/dist/runner-C0hCbYnD.mjs.map +0 -1
  109. package/dist/search-DG603UrT.mjs.map +0 -1
  110. package/dist/types-C4-fAxN3.d.mts.map +0 -1
  111. package/dist/types-DY5zk5HN.mjs.map +0 -1
@@ -4,13 +4,13 @@ import { i as slugify, r as RevisionRepository, t as ContentRepository } from ".
4
4
  import { r as encodeBase64, t as decodeBase64 } from "./base64-MBPo9ozB.mjs";
5
5
  import { n as decodeCursor, r as encodeCursor, t as EmDashValidationError } from "./types-CMMN0pNg.mjs";
6
6
  import { t as MediaRepository } from "./media-DqHVh136.mjs";
7
- import { a as stripCredentialHeaders, i as ssrfSafeFetch, o as validateExternalUrl, r as SsrfError, u as OptionsRepository } from "./apply-Bjfq_b4-.mjs";
8
- import { a as withTransaction, i as FTSManager, n as SchemaRegistry } from "./registry-D_w5HW4G.mjs";
7
+ import { a as stripCredentialHeaders, i as ssrfSafeFetch, o as validateExternalUrl, r as SsrfError, u as OptionsRepository } from "./apply-kC39ev1Z.mjs";
8
+ import { a as withTransaction, i as FTSManager, n as SchemaRegistry } from "./registry-BNYQKX_d.mjs";
9
9
  import { t as RedirectRepository } from "./redirect-DIfIni3r.mjs";
10
10
  import { t as BylineRepository } from "./byline-CL847F26.mjs";
11
11
  import { i as isI18nEnabled } from "./config-CKE8p9xM.mjs";
12
12
  import { n as getDb } from "./loader-fz8Q_3EO.mjs";
13
- import { i as pluginManifestSchema } from "./manifest-schema-Dcl0R6nM.mjs";
13
+ import { i as pluginManifestSchema } from "./manifest-schema-CL8DWO9b.mjs";
14
14
  import { t as generatePreviewToken } from "./tokens-DpgrkrXK.mjs";
15
15
  import { sql } from "kysely";
16
16
  import { ulid } from "ulidx";
@@ -323,20 +323,24 @@ var CommentRepository = class CommentRepository {
323
323
  }
324
324
  /**
325
325
  * Count comments grouped by status (for inbox badges)
326
+ *
327
+ * Uses four parallel COUNT queries with WHERE filters to leverage partial indexes
328
+ * (idx_comments_pending, idx_comments_approved, idx_comments_spam, idx_comments_trash)
329
+ * instead of a full table GROUP BY scan.
326
330
  */
327
331
  async countByStatus() {
328
- const rows = await this.db.selectFrom("_emdash_comments").select(["status"]).select((eb) => eb.fn.count("id").as("count")).groupBy("status").execute();
329
- const counts = {
330
- pending: 0,
331
- approved: 0,
332
- spam: 0,
333
- trash: 0
332
+ const [pending, approved, spam, trash] = await Promise.all([
333
+ this.db.selectFrom("_emdash_comments").select((eb) => eb.fn.count("id").as("count")).where("status", "=", "pending").executeTakeFirst(),
334
+ this.db.selectFrom("_emdash_comments").select((eb) => eb.fn.count("id").as("count")).where("status", "=", "approved").executeTakeFirst(),
335
+ this.db.selectFrom("_emdash_comments").select((eb) => eb.fn.count("id").as("count")).where("status", "=", "spam").executeTakeFirst(),
336
+ this.db.selectFrom("_emdash_comments").select((eb) => eb.fn.count("id").as("count")).where("status", "=", "trash").executeTakeFirst()
337
+ ]);
338
+ return {
339
+ pending: Number(pending?.count ?? 0),
340
+ approved: Number(approved?.count ?? 0),
341
+ spam: Number(spam?.count ?? 0),
342
+ trash: Number(trash?.count ?? 0)
334
343
  };
335
- for (const row of rows) {
336
- const status = row.status;
337
- if (status in counts) counts[status] = Number(row.count);
338
- }
339
- return counts;
340
344
  }
341
345
  /**
342
346
  * Count approved comments from a given email address.
@@ -2821,8 +2825,24 @@ const fieldTypeValues = z$1.enum([
2821
2825
  "file",
2822
2826
  "reference",
2823
2827
  "json",
2824
- "slug"
2828
+ "slug",
2829
+ "repeater"
2825
2830
  ]);
2831
+ const repeaterSubFieldSchema = z$1.object({
2832
+ slug: z$1.string().min(1).max(63).regex(slugPattern, "Invalid slug format"),
2833
+ type: z$1.enum([
2834
+ "string",
2835
+ "text",
2836
+ "number",
2837
+ "integer",
2838
+ "boolean",
2839
+ "datetime",
2840
+ "select"
2841
+ ]),
2842
+ label: z$1.string().min(1),
2843
+ required: z$1.boolean().optional(),
2844
+ options: z$1.array(z$1.string()).optional()
2845
+ });
2826
2846
  const fieldValidation = z$1.object({
2827
2847
  required: z$1.boolean().optional(),
2828
2848
  min: z$1.number().optional(),
@@ -2830,7 +2850,10 @@ const fieldValidation = z$1.object({
2830
2850
  minLength: z$1.number().int().min(0).optional(),
2831
2851
  maxLength: z$1.number().int().min(0).optional(),
2832
2852
  pattern: z$1.string().optional(),
2833
- options: z$1.array(z$1.string()).optional()
2853
+ options: z$1.array(z$1.string()).optional(),
2854
+ subFields: z$1.array(repeaterSubFieldSchema).min(1).optional(),
2855
+ minItems: z$1.number().int().min(0).optional(),
2856
+ maxItems: z$1.number().int().min(1).optional()
2834
2857
  }).optional();
2835
2858
  const fieldWidgetOptions = z$1.record(z$1.string(), z$1.unknown()).optional();
2836
2859
  const createCollectionBody = z$1.object({
@@ -5792,6 +5815,8 @@ var HookPipeline = class HookPipeline {
5792
5815
  this.registerPluginHook(plugin, "content:afterSave");
5793
5816
  this.registerPluginHook(plugin, "content:beforeDelete");
5794
5817
  this.registerPluginHook(plugin, "content:afterDelete");
5818
+ this.registerPluginHook(plugin, "content:afterPublish");
5819
+ this.registerPluginHook(plugin, "content:afterUnpublish");
5795
5820
  this.registerPluginHook(plugin, "media:beforeUpload");
5796
5821
  this.registerPluginHook(plugin, "media:afterUpload");
5797
5822
  this.registerPluginHook(plugin, "cron");
@@ -5822,6 +5847,8 @@ var HookPipeline = class HookPipeline {
5822
5847
  ["content:afterSave", "read:content"],
5823
5848
  ["content:beforeDelete", "read:content"],
5824
5849
  ["content:afterDelete", "read:content"],
5850
+ ["content:afterPublish", "read:content"],
5851
+ ["content:afterUnpublish", "read:content"],
5825
5852
  ["media:beforeUpload", "write:media"],
5826
5853
  ["media:afterUpload", "read:media"],
5827
5854
  ["comment:beforeCreate", "read:users"],
@@ -6100,6 +6127,72 @@ var HookPipeline = class HookPipeline {
6100
6127
  return results;
6101
6128
  }
6102
6129
  /**
6130
+ * Run content:afterPublish hooks (fire-and-forget).
6131
+ */
6132
+ async runContentAfterPublish(content, collection) {
6133
+ const hooks = this.getTypedHooks("content:afterPublish");
6134
+ const results = [];
6135
+ for (const hook of hooks) {
6136
+ const { handler } = hook;
6137
+ const event = {
6138
+ content,
6139
+ collection
6140
+ };
6141
+ const ctx = this.getContext(hook.pluginId);
6142
+ const start = Date.now();
6143
+ try {
6144
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
6145
+ results.push({
6146
+ success: true,
6147
+ pluginId: hook.pluginId,
6148
+ duration: Date.now() - start
6149
+ });
6150
+ } catch (error) {
6151
+ results.push({
6152
+ success: false,
6153
+ error: error instanceof Error ? error : new Error(String(error)),
6154
+ pluginId: hook.pluginId,
6155
+ duration: Date.now() - start
6156
+ });
6157
+ if (hook.errorPolicy === "abort") throw error;
6158
+ }
6159
+ }
6160
+ return results;
6161
+ }
6162
+ /**
6163
+ * Run content:afterUnpublish hooks (fire-and-forget).
6164
+ */
6165
+ async runContentAfterUnpublish(content, collection) {
6166
+ const hooks = this.getTypedHooks("content:afterUnpublish");
6167
+ const results = [];
6168
+ for (const hook of hooks) {
6169
+ const { handler } = hook;
6170
+ const event = {
6171
+ content,
6172
+ collection
6173
+ };
6174
+ const ctx = this.getContext(hook.pluginId);
6175
+ const start = Date.now();
6176
+ try {
6177
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
6178
+ results.push({
6179
+ success: true,
6180
+ pluginId: hook.pluginId,
6181
+ duration: Date.now() - start
6182
+ });
6183
+ } catch (error) {
6184
+ results.push({
6185
+ success: false,
6186
+ error: error instanceof Error ? error : new Error(String(error)),
6187
+ pluginId: hook.pluginId,
6188
+ duration: Date.now() - start
6189
+ });
6190
+ if (hook.errorPolicy === "abort") throw error;
6191
+ }
6192
+ }
6193
+ return results;
6194
+ }
6195
+ /**
6103
6196
  * Run media:beforeUpload hooks
6104
6197
  */
6105
6198
  async runMediaBeforeUpload(file) {
@@ -7064,6 +7157,20 @@ var PluginManager = class {
7064
7157
  return this.hookPipeline.runContentAfterDelete(id, collection);
7065
7158
  }
7066
7159
  /**
7160
+ * Run content:afterPublish hooks across all active plugins
7161
+ */
7162
+ async runContentAfterPublish(content, collection) {
7163
+ this.ensureInitialized();
7164
+ return this.hookPipeline.runContentAfterPublish(content, collection);
7165
+ }
7166
+ /**
7167
+ * Run content:afterUnpublish hooks across all active plugins
7168
+ */
7169
+ async runContentAfterUnpublish(content, collection) {
7170
+ this.ensureInitialized();
7171
+ return this.hookPipeline.runContentAfterUnpublish(content, collection);
7172
+ }
7173
+ /**
7067
7174
  * Run media:beforeUpload hooks across all active plugins
7068
7175
  */
7069
7176
  async runMediaBeforeUpload(file) {
@@ -8699,7 +8806,7 @@ async function getTermsForEntries(collection, entryIds, taxonomyName) {
8699
8806
  * Get entries by term (wraps getEmDashCollection)
8700
8807
  */
8701
8808
  async function getEntriesByTerm(collection, taxonomyName, termSlug) {
8702
- const { getEmDashCollection } = await import("./query-CS_iSj34.mjs").then((n) => n.a);
8809
+ const { getEmDashCollection } = await import("./query-BVYN0PJ6.mjs").then((n) => n.a);
8703
8810
  const { entries } = await getEmDashCollection(collection, { where: { [taxonomyName]: termSlug } });
8704
8811
  return entries;
8705
8812
  }
@@ -9208,4 +9315,4 @@ function extractSearchableFields(entry, fields) {
9208
9315
 
9209
9316
  //#endregion
9210
9317
  export { definePlugin as $, getFileSources as A, handleContentGetIncludingTrashed as At, PluginManager as B, handleContentUpdate as Bt, isPreviewRequest as C, handleContentCountScheduled as Ct, wxrSource as D, handleContentDiscardDraft as Dt, wordpressRestSource as E, handleContentDelete as Et, importReusableBlocksAsSections as F, handleContentRestore as Ft, devConsoleEmailDeliver as G, PluginRouteError as H, portableText as Ht, isStandardPluginDefinition as I, handleContentSchedule as It, createHookPipeline as J, EmailPipeline as K, NoopSandboxRunner as L, handleContentTranslations as Lt, getUrlSources as M, handleContentListTrashed as Mt, probeUrl as N, handleContentPermanentDelete as Nt, clearSources as O, handleContentDuplicate as Ot, registerSource as P, handleContentPublish as Pt, sanitizeHeadersForSandbox as Q, SandboxNotAvailableError as R, handleContentUnpublish as Rt, getPreviewToken as S, handleContentCompare as St, getPreviewUrl as T, handleContentCreate as Tt, PluginRouteRegistry as U, reference as Ut, createPluginManager as V, validateRev as Vt, DEV_CONSOLE_EMAIL_PLUGIN_ID as W, image as Wt, CronExecutor as X, resolveExclusiveHooks as Y, extractRequestMeta as Z, getTermsForEntries as _, handleRevisionList as _t, search as a, prosemirrorToPortableText as at, getCommentCount as b, computeContentHash as bt, getWidgetArea as c, getSections as ct, getEntriesByTerm as d, handleMediaCreate as dt, parseWxr as et, getEntryTerms as f, handleMediaDelete as ft, getTerm as g, handleRevisionGet as gt, getTaxonomyTerms as h, handleMediaUpdate as ht, getSuggestions as i, portableTextToProsemirror as it, getSource as j, handleContentList as jt, getAllSources as k, handleContentGet as kt, getWidgetAreas as l, PluginStateRepository as lt, getTaxonomyDefs as m, handleMediaList as mt, extractSearchableFields as n, isSafeHref as nt, searchCollection as o, loadBundleFromR2 as ot, getTaxonomyDef as p, handleMediaGet as pt, HookPipeline as q, getSearchStats as r, sanitizeHref as rt, searchWithDb as s, getSection as st, extractPlainText as t, parseWxrString as tt, getWidgetComponents as u, getCollectionInfo as ut, getMenu as v, handleRevisionRestore as vt, buildPreviewUrl as w, handleContentCountTrashed as wt, getComments as x, hashString as xt, getMenus as y, generateManifest as yt, createNoopSandboxRunner as z, handleContentUnschedule as zt };
9211
- //# sourceMappingURL=search-DG603UrT.mjs.map
9318
+ //# sourceMappingURL=search-C1gg67nN.mjs.map