@neopress/mcp 1.4.0 → 1.5.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;
@@ -294,7 +294,7 @@ interface SearchConsoleQueryResult {
294
294
  interface PageListParams {
295
295
  page?: number;
296
296
  limit?: number;
297
- status?: 'draft' | 'published';
297
+ status?: "draft" | "published";
298
298
  fields?: string[];
299
299
  /** When set, sort by created_at instead of path. */
300
300
  order?: SortOrder;
@@ -302,9 +302,9 @@ interface PageListParams {
302
302
  interface PageCreateParams {
303
303
  path: string;
304
304
  title?: string;
305
- type?: 'static' | 'dynamic';
306
- status?: 'draft' | 'published';
307
- visibility?: 'public' | 'hidden';
305
+ type?: "static" | "dynamic";
306
+ status?: "draft" | "published";
307
+ visibility?: "public" | "hidden";
308
308
  draftTsx?: string;
309
309
  draftI18n?: unknown;
310
310
  draftPublicLocales?: string[] | null;
@@ -317,7 +317,7 @@ interface PageUpdateParams {
317
317
  title?: string;
318
318
  type?: string;
319
319
  status?: string;
320
- visibility?: 'public' | 'hidden';
320
+ visibility?: string;
321
321
  draftTsx?: string;
322
322
  draftI18n?: unknown;
323
323
  draftPublicLocales?: string[] | null;
@@ -354,6 +354,12 @@ declare class CollectionsEndpoint {
354
354
  order?: SortOrder;
355
355
  }): Promise<Collection[]>;
356
356
  get(collectionId: number): Promise<Collection>;
357
+ /**
358
+ * Preset normalization (`normalizeCollectionPresetType` +
359
+ * `ensureCollectionPresetBaselineFields`) now runs server-side in
360
+ * `CollectionsApi.create`, which applies the identical pair in the identical
361
+ * order — the stored row is unchanged by the move to HTTP.
362
+ */
357
363
  create(data: CollectionCreateParams): Promise<Collection>;
358
364
  update(collectionId: number, data: Partial<CollectionCreateParams>): Promise<Collection>;
359
365
  delete(collectionId: number): Promise<void>;
@@ -362,10 +368,6 @@ declare class CollectionsEndpoint {
362
368
  draftSchema: unknown;
363
369
  prodSchema: unknown;
364
370
  }>;
365
- /**
366
- * Updates the collection's draft_schema directly in Supabase.
367
- * validateApiCollectionSchema (app-local) is skipped — CLI/MCP callers are trusted.
368
- */
369
371
  updateSchema(collectionId: number, schema: unknown): Promise<{
370
372
  collectionId: number;
371
373
  draftSchema: unknown;
@@ -377,7 +379,7 @@ declare class CollectionsEndpoint {
377
379
  interface EntryListParams {
378
380
  page?: number;
379
381
  limit?: number;
380
- status?: 'draft' | 'published' | 'archived';
382
+ status?: "draft" | "published" | "archived";
381
383
  locale?: string;
382
384
  /** created_at sort direction. Defaults to 'desc' (newest first). */
383
385
  order?: SortOrder;
@@ -401,6 +403,7 @@ interface EntryUpdateParams {
401
403
  declare class EntriesEndpoint {
402
404
  private readonly client;
403
405
  constructor(client: NeopressClient);
406
+ private get basePath();
404
407
  list(collectionId: number, params?: EntryListParams): Promise<PaginatedResponse<Entry>>;
405
408
  get(entryId: number): Promise<Entry>;
406
409
  create(collectionId: number, data: EntryCreateParams): Promise<Entry>;
@@ -491,7 +494,12 @@ declare class AssetsEndpoint {
491
494
  }): Promise<PaginatedResponse<Asset>>;
492
495
  get(assetId: number): Promise<Asset>;
493
496
  register(data: AssetRegisterParams): Promise<Asset>;
494
- update(assetId: number, data: Partial<Omit<AssetRegisterParams, 'assetUrl'>>): Promise<Asset>;
497
+ update(assetId: number, data: Partial<Omit<AssetRegisterParams, "assetUrl">>): Promise<Asset>;
498
+ /**
499
+ * Hard delete. The route additionally requires the caller to be the site
500
+ * owner, matching `assets_delete_policy` = `is_site_owner(site_id)` — the
501
+ * registry axes alone would have widened this (W7 mapping §3-B1).
502
+ */
495
503
  delete(assetId: number): Promise<void>;
496
504
  presign(data: AssetPresignParams): Promise<{
497
505
  presignedUrl: string;
@@ -502,6 +510,12 @@ declare class AssetsEndpoint {
502
510
  //#endregion
503
511
  //#region ../sdk/src/endpoints/site.d.ts
504
512
  interface SiteWithRole extends Site {
513
+ /** Project role of the caller on this site: "owner" | "admin" | "member". */
514
+ projectRole: string;
515
+ /**
516
+ * @deprecated Legacy site role derived from `projectRole` for backwards
517
+ * compatibility ("owner" | "admin" | "member"). Use `projectRole` instead.
518
+ */
505
519
  role: string;
506
520
  }
507
521
  interface SiteCreateParams {
@@ -509,18 +523,25 @@ interface SiteCreateParams {
509
523
  siteHandle?: string;
510
524
  prompt?: string;
511
525
  language?: string;
512
- placeholder?: boolean;
513
526
  }
514
527
  declare class SiteEndpoint {
515
528
  private readonly client;
516
529
  constructor(client: NeopressClient);
530
+ /**
531
+ * Global (not site-scoped): lists the caller's own memberships, so it does not
532
+ * hang off `siteBasePath`. The membership + soft-delete filters that RLS used
533
+ * to apply now live in the route.
534
+ */
517
535
  list(params?: {
518
536
  order?: SortOrder;
519
537
  }): Promise<SiteWithRole[]>;
520
538
  get(): Promise<Site>;
521
539
  create(data: SiteCreateParams): Promise<Site>;
522
- update(data: Partial<Pick<Site, 'name' | 'metadata' | 'localeConfig'>> & {
523
- globalCss?: string;
540
+ /**
541
+ * Site settings only. The stylesheet is not here — it lives on the layout
542
+ * (`updateLayout({ draftGlobalCss })`), which is what the reader renders.
543
+ */
544
+ update(data: Partial<Pick<Site, "name" | "metadata" | "localeConfig">> & {
524
545
  instructions?: unknown;
525
546
  }): Promise<Site>;
526
547
  getLayout(): Promise<SiteLayout>;
@@ -548,11 +569,17 @@ interface RedirectCreateParams {
548
569
  declare class RedirectsEndpoint {
549
570
  private readonly client;
550
571
  constructor(client: NeopressClient);
572
+ private get basePath();
551
573
  list(params?: {
552
574
  order?: SortOrder;
553
575
  }): Promise<RedirectRule[]>;
554
576
  create(data: RedirectCreateParams): Promise<RedirectRule>;
555
- private assertRedirectRuleWritable;
577
+ /**
578
+ * The proxy preflight that used to run here (`assertRedirectRuleWritable`)
579
+ * needs a DB read, so it moved into the route. Its two error codes —
580
+ * `REDIRECT_RULE_NOT_FOUND` and `REDIRECT_RULE_DASHBOARD_ONLY` — are returned
581
+ * by the server verbatim, so `NeopressApiError.code` is unchanged for callers.
582
+ */
556
583
  update(ruleId: number, data: Partial<RedirectCreateParams>): Promise<RedirectRule>;
557
584
  delete(ruleId: number): Promise<void>;
558
585
  }
@@ -580,6 +607,7 @@ interface EntryReferenceCreateParams {
580
607
  declare class EntryReferencesEndpoint {
581
608
  private readonly client;
582
609
  constructor(client: NeopressClient);
610
+ private get basePath();
583
611
  list(params?: EntryReferenceListParams): Promise<EntryReference[]>;
584
612
  create(data: EntryReferenceCreateParams): Promise<EntryReference>;
585
613
  delete(referenceId: number): Promise<void>;
@@ -630,9 +658,8 @@ declare class TemplatesEndpoint {
630
658
  /**
631
659
  * List templates across the sites the caller can access.
632
660
  *
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.
661
+ * Global (not site-scoped) — the accessible-site set is resolved server-side,
662
+ * where RLS used to do it.
636
663
  */
637
664
  list(params?: {
638
665
  namePrefix?: string;
@@ -642,10 +669,10 @@ declare class TemplatesEndpoint {
642
669
  }
643
670
  //#endregion
644
671
  //#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';
672
+ type HeadshotAgeBand = "young" | "middle";
673
+ type HeadshotGender = "male" | "female";
674
+ type HeadshotEthnicity = "asian" | "white" | "black" | "latino";
675
+ type HeadshotAttire = "formal" | "casual";
649
676
  interface HeadshotListParams {
650
677
  page?: number;
651
678
  limit?: number;
@@ -694,9 +721,11 @@ interface HeadshotDeleteResult {
694
721
  deleted: true;
695
722
  }
696
723
  /**
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.
724
+ * `headshot_pool` is a GLOBAL (not site-scoped) admin table, so these calls run
725
+ * over `/api/v1/headshots` — no `siteId` in the path — instead of the
726
+ * site-scoped `withAuth` routes (W7 T5). The routes gate on the super-admin
727
+ * user id, which is the same check the table's single RLS policy made; a
728
+ * non-super-admin now gets 403 where the direct-DB read returned an empty list.
700
729
  */
701
730
  declare class HeadshotsEndpoint {
702
731
  private readonly client;
@@ -709,8 +738,8 @@ declare class HeadshotsEndpoint {
709
738
  }
710
739
  //#endregion
711
740
  //#region ../sdk/src/endpoints/logos.d.ts
712
- type LogoType = 'wordmark' | 'lockup' | 'signature';
713
- type LogoTone = 'playful' | 'neutral' | 'serious';
741
+ type LogoType = "wordmark" | "lockup" | "signature";
742
+ type LogoTone = "playful" | "neutral" | "serious";
714
743
  interface LogoListParams {
715
744
  page?: number;
716
745
  limit?: number;
@@ -765,9 +794,11 @@ interface LogoDeleteResult {
765
794
  deleted: true;
766
795
  }
767
796
  /**
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.
797
+ * `logo_pool` is a GLOBAL (not site-scoped) admin table, so these calls run over
798
+ * `/api/v1/logos` — no `siteId` in the path — instead of the site-scoped
799
+ * `withAuth` routes (W7 T5). The routes gate on the super-admin user id, which
800
+ * is the same check the table's single RLS policy made; a non-super-admin now
801
+ * gets 403 where the direct-DB read returned an empty list.
771
802
  */
772
803
  declare class LogosEndpoint {
773
804
  private readonly client;
@@ -780,28 +811,29 @@ declare class LogosEndpoint {
780
811
  }
781
812
  //#endregion
782
813
  //#region ../sdk/src/client.d.ts
814
+ /**
815
+ * ⚠️ No `supabaseUrl` / `supabaseAnonKey`. This client speaks HTTP to
816
+ * `/api/v1/**` and nothing else — the direct-DB escape hatch (`client.db`) was
817
+ * removed in W7 so the seven tables it wrote to could have their
818
+ * `authenticated` write grants revoked
819
+ * (`docs/plan/2026-08-17-w7-sdk-retirement.md`). `check-dist-contract.mjs` in
820
+ * `@neopress/cli` / `@neopress/mcp` fails the build if either option returns.
821
+ */
783
822
  interface NeopressClientOptions {
784
823
  /** OAuth access token */
785
824
  accessToken?: string;
786
825
  /** Site ID to operate on */
787
826
  siteId: number | string;
788
- /** Base URL (default: https://app.neopress.ai) — used by orchestration/analytics (HTTP) routes */
827
+ /** Base URL (default: https://app.neopress.ai) */
789
828
  baseUrl?: string;
790
829
  /** Request timeout in ms (default: 30000) */
791
830
  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
831
  }
797
832
  declare class NeopressClient {
798
833
  private readonly baseUrl;
799
834
  private readonly accessToken;
800
835
  private readonly siteId;
801
836
  private readonly timeout;
802
- private readonly supabaseUrl?;
803
- private readonly supabaseAnonKey?;
804
- private _db;
805
837
  readonly pages: PagesEndpoint;
806
838
  readonly collections: CollectionsEndpoint;
807
839
  readonly entries: EntriesEndpoint;
@@ -817,26 +849,6 @@ declare class NeopressClient {
817
849
  readonly logos: LogosEndpoint;
818
850
  constructor(options: NeopressClientOptions);
819
851
  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
852
  request<T>(method: string, path: string, body?: unknown): Promise<T>;
841
853
  get<T>(path: string): Promise<ApiResponse<T>>;
842
854
  getList<T>(path: string): Promise<PaginatedResponse<T>>;
@@ -895,11 +907,11 @@ declare function createMemoryRemoteSiteSelectionStore(): RemoteSiteSelectionStor
895
907
  declare function createRemoteToolContext(options: RemoteToolContextOptions): ToolContext;
896
908
  //#endregion
897
909
  //#region src/remote/http-server.d.ts
898
- type RemoteMcpAuthMode = 'oauth' | 'none';
910
+ type RemoteMcpAuthMode = "oauth" | "none";
899
911
  interface NeopressMcpHttpServerOptions {
900
912
  authMode?: RemoteMcpAuthMode;
901
913
  baseUrl?: string;
902
- corsOrigins?: string[] | '*';
914
+ corsOrigins?: string[] | "*";
903
915
  fetch?: typeof fetch;
904
916
  host?: string;
905
917
  openaiAppsChallengeToken?: string;