@neopress/mcp 1.4.0 → 1.6.0

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.d.ts CHANGED
@@ -26,7 +26,7 @@ interface PaginatedResponse<T> {
26
26
  pagination: PaginationMeta;
27
27
  }
28
28
  /** Sort direction for list endpoints that support opt-in created_at ordering. */
29
- type SortOrder = 'asc' | 'desc';
29
+ type SortOrder = "asc" | "desc";
30
30
  interface Site {
31
31
  id: number;
32
32
  name: string | null;
@@ -39,7 +39,7 @@ interface Site {
39
39
  localeConfig: {
40
40
  defaultLocale: string;
41
41
  locales: string[];
42
- localePrefix?: 'as-needed';
42
+ localePrefix?: "as-needed";
43
43
  } | null;
44
44
  createdAt: string | null;
45
45
  updatedAt: string | null;
@@ -176,7 +176,7 @@ interface RedirectRule {
176
176
  siteId: number;
177
177
  source: string;
178
178
  destination: string;
179
- mode: 'redirect' | 'proxy';
179
+ mode: "redirect" | "proxy";
180
180
  redirectType: number;
181
181
  includeChildren: boolean;
182
182
  preservePath: boolean;
@@ -262,7 +262,7 @@ interface AnalyticsDateRangeParams {
262
262
  limit?: number;
263
263
  params?: Record<string, AnalyticsQueryValue>;
264
264
  }
265
- type SearchConsoleDimension = 'query' | 'page' | 'country' | 'device';
265
+ type SearchConsoleDimension = "query" | "page" | "country" | "device";
266
266
  interface SearchConsoleQueryParams {
267
267
  dateFrom: string;
268
268
  dateTo: string;
@@ -289,12 +289,108 @@ interface SearchConsoleQueryResult {
289
289
  };
290
290
  error?: string;
291
291
  }
292
+ type AnalyticsEventType = "custom" | "page" | "click" | "form" | "scroll" | "visibility" | "dwell";
293
+ type FunnelFilterField = "event.path" | "event.url" | "event.referrer" | "event.referrer_source" | "event.property" | "session.referrer" | "session.referrer_source" | "session.traffic_category" | "session.utm_source" | "session.utm_medium" | "session.utm_campaign" | "session.utm_content" | "session.utm_term";
294
+ type FunnelFilterOperator = "eq" | "neq" | "contains" | "not_contains" | "starts_with" | "ends_with" | "exists" | "not_exists" | "gt" | "gte" | "lt" | "lte";
295
+ type AnalyticsFunnelFilterCondition = {
296
+ kind: "condition";
297
+ field: FunnelFilterField;
298
+ operator: FunnelFilterOperator;
299
+ key?: string;
300
+ value?: string | number;
301
+ };
302
+ type AnalyticsFunnelFilterGroup = {
303
+ kind: "group";
304
+ op: "and" | "or";
305
+ children: AnalyticsFunnelFilterNode[];
306
+ };
307
+ type AnalyticsFunnelFilterNode = AnalyticsFunnelFilterGroup | AnalyticsFunnelFilterCondition;
308
+ type AnalyticsFunnelFilter = {
309
+ version: 1;
310
+ root: AnalyticsFunnelFilterGroup;
311
+ };
312
+ interface AnalyticsEventDefinition {
313
+ id: string;
314
+ chart_color: string | null;
315
+ name: string;
316
+ chart_visible: boolean;
317
+ is_pinned: boolean;
318
+ event_type: AnalyticsEventType;
319
+ event_name: string;
320
+ path: string;
321
+ selector: string;
322
+ form_id: string;
323
+ scroll_depth: number;
324
+ dwell_seconds: number;
325
+ tracking_version: number;
326
+ created_at: string;
327
+ updated_at: string;
328
+ }
329
+ interface AnalyticsEventDefinitionInput {
330
+ /** Optional client UUID; reuse it with the same payload after an uncertain create response. */
331
+ id?: string;
332
+ name: string;
333
+ eventType: AnalyticsEventType;
334
+ eventName?: string;
335
+ path?: string;
336
+ selector?: string;
337
+ formId?: string;
338
+ scrollDepth?: number;
339
+ dwellSeconds?: number;
340
+ }
341
+ type AnalyticsEventDefinitionUpdate = AnalyticsEventDefinitionInput | {
342
+ name: string;
343
+ };
344
+ interface AnalyticsEventDisplayUpdate {
345
+ chartVisible?: boolean;
346
+ pinned?: boolean;
347
+ chartColor?: string;
348
+ }
349
+ interface AnalyticsFunnelStepInput {
350
+ eventId: string;
351
+ path?: string;
352
+ filter?: AnalyticsFunnelFilter;
353
+ }
354
+ interface AnalyticsFunnelStep {
355
+ event_id: string;
356
+ path?: string;
357
+ filter?: AnalyticsFunnelFilter;
358
+ }
359
+ interface AnalyticsFunnelDefinition {
360
+ invalid?: true;
361
+ id: string;
362
+ name: string;
363
+ steps: AnalyticsFunnelStep[];
364
+ session_only: boolean;
365
+ window_minutes: number;
366
+ created_at: string;
367
+ updated_at: string;
368
+ }
369
+ interface AnalyticsTargets {
370
+ pages: Array<{
371
+ id: number;
372
+ name: string;
373
+ path: string;
374
+ locale: string;
375
+ }>;
376
+ forms: Array<{
377
+ id: number;
378
+ name: string;
379
+ }>;
380
+ }
381
+ interface AnalyticsFunnelDefinitionInput {
382
+ id?: string;
383
+ name: string;
384
+ steps: AnalyticsFunnelStepInput[];
385
+ windowMode: "session" | "time";
386
+ windowHours?: number;
387
+ }
292
388
  //#endregion
293
389
  //#region ../sdk/src/endpoints/pages.d.ts
294
390
  interface PageListParams {
295
391
  page?: number;
296
392
  limit?: number;
297
- status?: 'draft' | 'published';
393
+ status?: "draft" | "published";
298
394
  fields?: string[];
299
395
  /** When set, sort by created_at instead of path. */
300
396
  order?: SortOrder;
@@ -302,9 +398,9 @@ interface PageListParams {
302
398
  interface PageCreateParams {
303
399
  path: string;
304
400
  title?: string;
305
- type?: 'static' | 'dynamic';
306
- status?: 'draft' | 'published';
307
- visibility?: 'public' | 'hidden';
401
+ type?: "static" | "dynamic";
402
+ status?: "draft" | "published";
403
+ visibility?: "public" | "hidden";
308
404
  draftTsx?: string;
309
405
  draftI18n?: unknown;
310
406
  draftPublicLocales?: string[] | null;
@@ -317,7 +413,7 @@ interface PageUpdateParams {
317
413
  title?: string;
318
414
  type?: string;
319
415
  status?: string;
320
- visibility?: 'public' | 'hidden';
416
+ visibility?: string;
321
417
  draftTsx?: string;
322
418
  draftI18n?: unknown;
323
419
  draftPublicLocales?: string[] | null;
@@ -354,6 +450,12 @@ declare class CollectionsEndpoint {
354
450
  order?: SortOrder;
355
451
  }): Promise<Collection[]>;
356
452
  get(collectionId: number): Promise<Collection>;
453
+ /**
454
+ * Preset normalization (`normalizeCollectionPresetType` +
455
+ * `ensureCollectionPresetBaselineFields`) now runs server-side in
456
+ * `CollectionsApi.create`, which applies the identical pair in the identical
457
+ * order — the stored row is unchanged by the move to HTTP.
458
+ */
357
459
  create(data: CollectionCreateParams): Promise<Collection>;
358
460
  update(collectionId: number, data: Partial<CollectionCreateParams>): Promise<Collection>;
359
461
  delete(collectionId: number): Promise<void>;
@@ -362,10 +464,6 @@ declare class CollectionsEndpoint {
362
464
  draftSchema: unknown;
363
465
  prodSchema: unknown;
364
466
  }>;
365
- /**
366
- * Updates the collection's draft_schema directly in Supabase.
367
- * validateApiCollectionSchema (app-local) is skipped — CLI/MCP callers are trusted.
368
- */
369
467
  updateSchema(collectionId: number, schema: unknown): Promise<{
370
468
  collectionId: number;
371
469
  draftSchema: unknown;
@@ -377,7 +475,7 @@ declare class CollectionsEndpoint {
377
475
  interface EntryListParams {
378
476
  page?: number;
379
477
  limit?: number;
380
- status?: 'draft' | 'published' | 'archived';
478
+ status?: "draft" | "published" | "archived";
381
479
  locale?: string;
382
480
  /** created_at sort direction. Defaults to 'desc' (newest first). */
383
481
  order?: SortOrder;
@@ -401,9 +499,12 @@ interface EntryUpdateParams {
401
499
  declare class EntriesEndpoint {
402
500
  private readonly client;
403
501
  constructor(client: NeopressClient);
502
+ private get basePath();
404
503
  list(collectionId: number, params?: EntryListParams): Promise<PaginatedResponse<Entry>>;
405
504
  get(entryId: number): Promise<Entry>;
406
505
  create(collectionId: number, data: EntryCreateParams): Promise<Entry>;
506
+ /** Copy source content into a linked locale draft, or return its existing translation. */
507
+ createTranslation(entryId: number, locale: string): Promise<Entry>;
407
508
  update(entryId: number, data: EntryUpdateParams): Promise<Entry>;
408
509
  delete(entryId: number): Promise<void>;
409
510
  revalidateReaderCache(entryId: number): Promise<void>;
@@ -491,7 +592,12 @@ declare class AssetsEndpoint {
491
592
  }): Promise<PaginatedResponse<Asset>>;
492
593
  get(assetId: number): Promise<Asset>;
493
594
  register(data: AssetRegisterParams): Promise<Asset>;
494
- update(assetId: number, data: Partial<Omit<AssetRegisterParams, 'assetUrl'>>): Promise<Asset>;
595
+ update(assetId: number, data: Partial<Omit<AssetRegisterParams, "assetUrl">>): Promise<Asset>;
596
+ /**
597
+ * Hard delete. The route additionally requires the caller to be the site
598
+ * owner, matching `assets_delete_policy` = `is_site_owner(site_id)` — the
599
+ * registry axes alone would have widened this (W7 mapping §3-B1).
600
+ */
495
601
  delete(assetId: number): Promise<void>;
496
602
  presign(data: AssetPresignParams): Promise<{
497
603
  presignedUrl: string;
@@ -502,6 +608,12 @@ declare class AssetsEndpoint {
502
608
  //#endregion
503
609
  //#region ../sdk/src/endpoints/site.d.ts
504
610
  interface SiteWithRole extends Site {
611
+ /** Project role of the caller on this site: "owner" | "admin" | "member". */
612
+ projectRole: string;
613
+ /**
614
+ * @deprecated Legacy site role derived from `projectRole` for backwards
615
+ * compatibility ("owner" | "admin" | "member"). Use `projectRole` instead.
616
+ */
505
617
  role: string;
506
618
  }
507
619
  interface SiteCreateParams {
@@ -509,18 +621,25 @@ interface SiteCreateParams {
509
621
  siteHandle?: string;
510
622
  prompt?: string;
511
623
  language?: string;
512
- placeholder?: boolean;
513
624
  }
514
625
  declare class SiteEndpoint {
515
626
  private readonly client;
516
627
  constructor(client: NeopressClient);
628
+ /**
629
+ * Global (not site-scoped): lists the caller's own memberships, so it does not
630
+ * hang off `siteBasePath`. The membership + soft-delete filters that RLS used
631
+ * to apply now live in the route.
632
+ */
517
633
  list(params?: {
518
634
  order?: SortOrder;
519
635
  }): Promise<SiteWithRole[]>;
520
636
  get(): Promise<Site>;
521
637
  create(data: SiteCreateParams): Promise<Site>;
522
- update(data: Partial<Pick<Site, 'name' | 'metadata' | 'localeConfig'>> & {
523
- globalCss?: string;
638
+ /**
639
+ * Site settings only. The stylesheet is not here — it lives on the layout
640
+ * (`updateLayout({ draftGlobalCss })`), which is what the reader renders.
641
+ */
642
+ update(data: Partial<Pick<Site, "name" | "metadata" | "localeConfig">> & {
524
643
  instructions?: unknown;
525
644
  }): Promise<Site>;
526
645
  getLayout(): Promise<SiteLayout>;
@@ -548,11 +667,17 @@ interface RedirectCreateParams {
548
667
  declare class RedirectsEndpoint {
549
668
  private readonly client;
550
669
  constructor(client: NeopressClient);
670
+ private get basePath();
551
671
  list(params?: {
552
672
  order?: SortOrder;
553
673
  }): Promise<RedirectRule[]>;
554
674
  create(data: RedirectCreateParams): Promise<RedirectRule>;
555
- private assertRedirectRuleWritable;
675
+ /**
676
+ * The proxy preflight that used to run here (`assertRedirectRuleWritable`)
677
+ * needs a DB read, so it moved into the route. Its two error codes —
678
+ * `REDIRECT_RULE_NOT_FOUND` and `REDIRECT_RULE_DASHBOARD_ONLY` — are returned
679
+ * by the server verbatim, so `NeopressApiError.code` is unchanged for callers.
680
+ */
556
681
  update(ruleId: number, data: Partial<RedirectCreateParams>): Promise<RedirectRule>;
557
682
  delete(ruleId: number): Promise<void>;
558
683
  }
@@ -580,6 +705,7 @@ interface EntryReferenceCreateParams {
580
705
  declare class EntryReferencesEndpoint {
581
706
  private readonly client;
582
707
  constructor(client: NeopressClient);
708
+ private get basePath();
583
709
  list(params?: EntryReferenceListParams): Promise<EntryReference[]>;
584
710
  create(data: EntryReferenceCreateParams): Promise<EntryReference>;
585
711
  delete(referenceId: number): Promise<void>;
@@ -588,6 +714,8 @@ declare class EntryReferencesEndpoint {
588
714
  //#region ../sdk/src/endpoints/analytics.d.ts
589
715
  declare class AnalyticsEndpoint {
590
716
  private readonly client;
717
+ readonly events: AnalyticsEventsEndpoint;
718
+ readonly funnels: AnalyticsFunnelsEndpoint;
591
719
  constructor(client: NeopressClient);
592
720
  private get basePath();
593
721
  query(params: AnalyticsQueryParams): Promise<AnalyticsQueryResult>;
@@ -598,6 +726,30 @@ declare class AnalyticsEndpoint {
598
726
  formAnalytics(params?: AnalyticsDateRangeParams): Promise<AnalyticsQueryResult>;
599
727
  crawlerSummary(params?: AnalyticsDateRangeParams): Promise<AnalyticsQueryResult>;
600
728
  searchConsole(params: SearchConsoleQueryParams): Promise<SearchConsoleQueryResult>;
729
+ /** Page/form targets that can be referenced by an event definition. */
730
+ targets(): Promise<AnalyticsTargets>;
731
+ }
732
+ declare class AnalyticsEventsEndpoint {
733
+ private readonly client;
734
+ constructor(client: NeopressClient);
735
+ private get basePath();
736
+ list(): Promise<AnalyticsEventDefinition[]>;
737
+ get(eventId: string): Promise<AnalyticsEventDefinition>;
738
+ create(data: AnalyticsEventDefinitionInput): Promise<AnalyticsEventDefinition>;
739
+ update(eventId: string, data: AnalyticsEventDefinitionUpdate | {
740
+ display: AnalyticsEventDisplayUpdate;
741
+ }): Promise<AnalyticsEventDefinition>;
742
+ delete(eventId: string): Promise<void>;
743
+ }
744
+ declare class AnalyticsFunnelsEndpoint {
745
+ private readonly client;
746
+ constructor(client: NeopressClient);
747
+ private get basePath();
748
+ list(): Promise<AnalyticsFunnelDefinition[]>;
749
+ get(funnelId: string): Promise<AnalyticsFunnelDefinition>;
750
+ create(data: AnalyticsFunnelDefinitionInput): Promise<AnalyticsFunnelDefinition>;
751
+ update(funnelId: string, data: AnalyticsFunnelDefinitionInput): Promise<AnalyticsFunnelDefinition>;
752
+ delete(funnelId: string): Promise<void>;
601
753
  }
602
754
  //#endregion
603
755
  //#region ../sdk/src/endpoints/templates.d.ts
@@ -630,9 +782,8 @@ declare class TemplatesEndpoint {
630
782
  /**
631
783
  * List templates across the sites the caller can access.
632
784
  *
633
- * Direct-DB: `templates` is public-read and `sites` RLS scopes the visible set
634
- * (own active memberships, or all sites for the super admin), so no server
635
- * route is needed — the two RLS-scoped queries reproduce the old handler.
785
+ * Global (not site-scoped) — the accessible-site set is resolved server-side,
786
+ * where RLS used to do it.
636
787
  */
637
788
  list(params?: {
638
789
  namePrefix?: string;
@@ -642,10 +793,10 @@ declare class TemplatesEndpoint {
642
793
  }
643
794
  //#endregion
644
795
  //#region ../sdk/src/endpoints/headshots.d.ts
645
- type HeadshotAgeBand = 'young' | 'middle';
646
- type HeadshotGender = 'male' | 'female';
647
- type HeadshotEthnicity = 'asian' | 'white' | 'black' | 'latino';
648
- type HeadshotAttire = 'formal' | 'casual';
796
+ type HeadshotAgeBand = "young" | "middle";
797
+ type HeadshotGender = "male" | "female";
798
+ type HeadshotEthnicity = "asian" | "white" | "black" | "latino";
799
+ type HeadshotAttire = "formal" | "casual";
649
800
  interface HeadshotListParams {
650
801
  page?: number;
651
802
  limit?: number;
@@ -694,9 +845,11 @@ interface HeadshotDeleteResult {
694
845
  deleted: true;
695
846
  }
696
847
  /**
697
- * headshot_pool is a GLOBAL (not site-scoped) admin table. RLS exposes it only to
698
- * the super-admin user, so these direct-DB calls return empty/forbidden for any
699
- * other account. No site id is used.
848
+ * `headshot_pool` is a GLOBAL (not site-scoped) admin table, so these calls run
849
+ * over `/api/v1/headshots` — no `siteId` in the path — instead of the
850
+ * site-scoped `withAuth` routes (W7 T5). The routes gate on the super-admin
851
+ * user id, which is the same check the table's single RLS policy made; a
852
+ * non-super-admin now gets 403 where the direct-DB read returned an empty list.
700
853
  */
701
854
  declare class HeadshotsEndpoint {
702
855
  private readonly client;
@@ -709,8 +862,8 @@ declare class HeadshotsEndpoint {
709
862
  }
710
863
  //#endregion
711
864
  //#region ../sdk/src/endpoints/logos.d.ts
712
- type LogoType = 'wordmark' | 'lockup' | 'signature';
713
- type LogoTone = 'playful' | 'neutral' | 'serious';
865
+ type LogoType = "wordmark" | "lockup" | "signature";
866
+ type LogoTone = "playful" | "neutral" | "serious";
714
867
  interface LogoListParams {
715
868
  page?: number;
716
869
  limit?: number;
@@ -765,9 +918,11 @@ interface LogoDeleteResult {
765
918
  deleted: true;
766
919
  }
767
920
  /**
768
- * logo_pool is a GLOBAL (not site-scoped) admin table. RLS exposes it only to the
769
- * super-admin user, so these direct-DB calls return empty/forbidden for any other
770
- * account. No site id is used.
921
+ * `logo_pool` is a GLOBAL (not site-scoped) admin table, so these calls run over
922
+ * `/api/v1/logos` — no `siteId` in the path — instead of the site-scoped
923
+ * `withAuth` routes (W7 T5). The routes gate on the super-admin user id, which
924
+ * is the same check the table's single RLS policy made; a non-super-admin now
925
+ * gets 403 where the direct-DB read returned an empty list.
771
926
  */
772
927
  declare class LogosEndpoint {
773
928
  private readonly client;
@@ -780,28 +935,29 @@ declare class LogosEndpoint {
780
935
  }
781
936
  //#endregion
782
937
  //#region ../sdk/src/client.d.ts
938
+ /**
939
+ * ⚠️ No `supabaseUrl` / `supabaseAnonKey`. This client speaks HTTP to
940
+ * `/api/v1/**` and nothing else — the direct-DB escape hatch (`client.db`) was
941
+ * removed in W7 so the seven tables it wrote to could have their
942
+ * `authenticated` write grants revoked
943
+ * (`docs/plan/2026-08-17-w7-sdk-retirement.md`). `check-dist-contract.mjs` in
944
+ * `@neopress/cli` / `@neopress/mcp` fails the build if either option returns.
945
+ */
783
946
  interface NeopressClientOptions {
784
947
  /** OAuth access token */
785
948
  accessToken?: string;
786
949
  /** Site ID to operate on */
787
950
  siteId: number | string;
788
- /** Base URL (default: https://app.neopress.ai) — used by orchestration/analytics (HTTP) routes */
951
+ /** Base URL (default: https://app.neopress.ai) */
789
952
  baseUrl?: string;
790
953
  /** Request timeout in ms (default: 30000) */
791
954
  timeout?: number;
792
- /** Supabase project URL — enables direct-DB reads/CRUD (transparent routing). */
793
- supabaseUrl?: string;
794
- /** Supabase anon key (paired with the user accessToken so RLS applies). */
795
- supabaseAnonKey?: string;
796
955
  }
797
956
  declare class NeopressClient {
798
957
  private readonly baseUrl;
799
958
  private readonly accessToken;
800
959
  private readonly siteId;
801
960
  private readonly timeout;
802
- private readonly supabaseUrl?;
803
- private readonly supabaseAnonKey?;
804
- private _db;
805
961
  readonly pages: PagesEndpoint;
806
962
  readonly collections: CollectionsEndpoint;
807
963
  readonly entries: EntriesEndpoint;
@@ -817,26 +973,6 @@ declare class NeopressClient {
817
973
  readonly logos: LogosEndpoint;
818
974
  constructor(options: NeopressClientOptions);
819
975
  get siteBasePath(): string;
820
- /** Numeric site id for direct DB queries. */
821
- get siteIdNumber(): number;
822
- /**
823
- * Authenticated user's profile id, decoded locally from the access token's
824
- * JWT `sub` claim (no network round-trip). Returns null if there is no token
825
- * or it cannot be parsed. Subsequent DB queries are RLS-protected, so a local
826
- * decode is sufficient — no server-side validation is required here.
827
- */
828
- get authUserId(): string | null;
829
- /** Mirror of v1 parsePagination(defaultLimit=20, maxLimit=100). */
830
- resolvePagination(params?: {
831
- page?: number;
832
- limit?: number;
833
- }): {
834
- page: number;
835
- limit: number;
836
- offset: number;
837
- };
838
- /** Build the paginated envelope matching the v1 API. */
839
- paginationMeta(page: number, limit: number, offset: number, totalCount: number): PaginationMeta;
840
976
  request<T>(method: string, path: string, body?: unknown): Promise<T>;
841
977
  get<T>(path: string): Promise<ApiResponse<T>>;
842
978
  getList<T>(path: string): Promise<PaginatedResponse<T>>;
@@ -895,11 +1031,11 @@ declare function createMemoryRemoteSiteSelectionStore(): RemoteSiteSelectionStor
895
1031
  declare function createRemoteToolContext(options: RemoteToolContextOptions): ToolContext;
896
1032
  //#endregion
897
1033
  //#region src/remote/http-server.d.ts
898
- type RemoteMcpAuthMode = 'oauth' | 'none';
1034
+ type RemoteMcpAuthMode = "oauth" | "none";
899
1035
  interface NeopressMcpHttpServerOptions {
900
1036
  authMode?: RemoteMcpAuthMode;
901
1037
  baseUrl?: string;
902
- corsOrigins?: string[] | '*';
1038
+ corsOrigins?: string[] | "*";
903
1039
  fetch?: typeof fetch;
904
1040
  host?: string;
905
1041
  openaiAppsChallengeToken?: string;