astro-ghostcms/.pnpm-store/v3/files/6a/3c4b08a10993fa6522c9be52ad2...

1297 lines
42 KiB
Plaintext

'use strict';
var zod = require('zod');
var jose = require('jose');
// src/schemas/authors.ts
var ghostIdentitySchema = zod.z.object({
slug: zod.z.string(),
id: zod.z.string()
});
var ghostIdentityInputSchema = zod.z.object({
slug: zod.z.string().optional(),
id: zod.z.string().optional(),
email: zod.z.string().email().optional()
});
var ghostMetaSchema = zod.z.object({
pagination: zod.z.object({
pages: zod.z.number(),
page: zod.z.number(),
limit: zod.z.union([zod.z.number(), zod.z.literal("all")]),
total: zod.z.number(),
prev: zod.z.number().nullable(),
next: zod.z.number().nullable()
})
});
var ghostExcerptSchema = zod.z.object({
excerpt: zod.z.string().optional(),
custom_excerpt: zod.z.string().optional()
});
var ghostCodeInjectionSchema = zod.z.object({
codeinjection_head: zod.z.string().nullable(),
codeinjection_foot: zod.z.string().nullable()
});
var ghostFacebookSchema = zod.z.object({
og_image: zod.z.string().nullable(),
og_title: zod.z.string().nullable(),
og_description: zod.z.string().nullable()
});
var ghostTwitterSchema = zod.z.object({
twitter_image: zod.z.string().nullable(),
twitter_title: zod.z.string().nullable(),
twitter_description: zod.z.string().nullable()
});
var ghostSocialMediaSchema = zod.z.object({
...ghostFacebookSchema.shape,
...ghostTwitterSchema.shape
});
var ghostMetadataSchema = zod.z.object({
meta_title: zod.z.string().nullable(),
meta_description: zod.z.string().nullable()
});
var ghostVisibilitySchema = zod.z.union([
zod.z.literal("public"),
zod.z.literal("members"),
zod.z.literal("none"),
zod.z.literal("internal"),
zod.z.literal("paid"),
zod.z.literal("tiers")
]);
var apiVersionsSchema = zod.z.string().regex(/^v5\.\d+/).default("v5.0");
var contentAPICredentialsSchema = zod.z.object({
key: zod.z.string().regex(/[0-9a-f]{26}/, { message: "'key' must have 26 hex characters" }),
version: apiVersionsSchema,
url: zod.z.string().url()
});
var adminAPICredentialsSchema = zod.z.object({
key: zod.z.string().regex(/[0-9a-f]{24}:[0-9a-f]{64}/, {
message: "'key' must have the following format {A}:{B}, where A is 24 hex characters and B is 64 hex characters"
}),
version: apiVersionsSchema,
url: zod.z.string().url()
});
var slugOrIdSchema = zod.z.union([zod.z.object({ slug: zod.z.string() }), zod.z.object({ id: zod.z.string() })]);
var emailOrIdSchema = zod.z.union([
zod.z.object({ email: zod.z.string().email() }),
zod.z.object({ id: zod.z.string() })
]);
var identitySchema = zod.z.union([
zod.z.object({ email: zod.z.string().email() }),
zod.z.object({ id: zod.z.string() }),
zod.z.object({ slug: zod.z.string() })
]);
// src/schemas/authors.ts
var baseAuthorsSchema = zod.z.object({
...ghostIdentitySchema.shape,
...ghostMetadataSchema.shape,
name: zod.z.string(),
profile_image: zod.z.string().nullable(),
cover_image: zod.z.string().nullable(),
bio: zod.z.string().nullable(),
website: zod.z.string().nullable(),
location: zod.z.string().nullable(),
facebook: zod.z.string().nullable(),
twitter: zod.z.string().nullable(),
count: zod.z.object({
posts: zod.z.number()
}).optional(),
url: zod.z.string()
});
var baseTagsSchema = zod.z.object({
...ghostIdentitySchema.shape,
...ghostMetadataSchema.shape,
...ghostCodeInjectionSchema.shape,
...ghostSocialMediaSchema.shape,
name: zod.z.string(),
description: zod.z.string().nullable(),
feature_image: zod.z.string().nullable(),
visibility: ghostVisibilitySchema,
canonical_url: zod.z.string().nullable(),
accent_color: zod.z.string().nullable(),
url: zod.z.string(),
created_at: zod.z.string().nullish(),
updated_at: zod.z.string().nullish(),
count: zod.z.object({
posts: zod.z.number()
}).optional()
});
// src/schemas/pages.ts
var postsAuthorSchema = baseAuthorsSchema.extend({
url: zod.z.string().nullish()
});
var basePagesSchema = zod.z.object({
...ghostIdentitySchema.shape,
...ghostMetadataSchema.shape,
title: zod.z.string(),
html: zod.z.string().nullish(),
plaintext: zod.z.string().nullish(),
comment_id: zod.z.string().nullable(),
feature_image: zod.z.string().nullable(),
feature_image_alt: zod.z.string().nullable(),
feature_image_caption: zod.z.string().nullable(),
featured: zod.z.boolean(),
custom_excerpt: zod.z.string().nullable(),
...ghostCodeInjectionSchema.shape,
...ghostSocialMediaSchema.shape,
visibility: ghostVisibilitySchema,
custom_template: zod.z.string().nullable(),
canonical_url: zod.z.string().nullable(),
authors: zod.z.array(postsAuthorSchema).optional(),
tags: zod.z.array(baseTagsSchema).optional(),
primary_author: postsAuthorSchema.nullish(),
primary_tag: baseTagsSchema.nullish(),
url: zod.z.string(),
excerpt: zod.z.string().nullish(),
reading_time: zod.z.number().optional().default(0),
created_at: zod.z.string(),
updated_at: zod.z.string().nullish(),
published_at: zod.z.string().nullable(),
email_subject: zod.z.string().nullish(),
is_page: zod.z.boolean().default(true)
});
var postsAuthorSchema2 = baseAuthorsSchema.extend({
url: zod.z.string().nullish()
});
var basePostsSchema = zod.z.object({
...ghostIdentitySchema.shape,
...ghostMetadataSchema.shape,
title: zod.z.string(),
html: zod.z.string().nullish(),
plaintext: zod.z.string().nullish(),
comment_id: zod.z.string().nullable(),
feature_image: zod.z.string().nullable(),
feature_image_alt: zod.z.string().nullable(),
feature_image_caption: zod.z.string().nullable(),
featured: zod.z.boolean(),
custom_excerpt: zod.z.string().nullable(),
...ghostCodeInjectionSchema.shape,
...ghostSocialMediaSchema.shape,
visibility: ghostVisibilitySchema,
custom_template: zod.z.string().nullable(),
canonical_url: zod.z.string().nullable(),
authors: zod.z.array(postsAuthorSchema2).optional(),
tags: zod.z.array(baseTagsSchema).optional(),
primary_author: postsAuthorSchema2.nullish(),
primary_tag: baseTagsSchema.nullish(),
url: zod.z.string(),
excerpt: zod.z.string().nullable(),
reading_time: zod.z.number().optional().default(0),
created_at: zod.z.string(),
updated_at: zod.z.string().nullish(),
published_at: zod.z.string().nullable(),
email_subject: zod.z.string().nullish(),
is_page: zod.z.boolean().default(false)
});
var baseSettingsSchema = zod.z.object({
title: zod.z.string(),
description: zod.z.string(),
logo: zod.z.string().nullable(),
icon: zod.z.string().nullable(),
accent_color: zod.z.string().nullable(),
cover_image: zod.z.string().nullable(),
facebook: zod.z.string().nullable(),
twitter: zod.z.string().nullable(),
lang: zod.z.string(),
timezone: zod.z.string(),
codeinjection_head: zod.z.string().nullable(),
codeinjection_foot: zod.z.string().nullable(),
navigation: zod.z.array(
zod.z.object({
label: zod.z.string(),
url: zod.z.string()
})
),
secondary_navigation: zod.z.array(
zod.z.object({
label: zod.z.string(),
url: zod.z.string()
})
),
meta_title: zod.z.string().nullable(),
meta_description: zod.z.string().nullable(),
og_image: zod.z.string().nullable(),
og_title: zod.z.string().nullable(),
og_description: zod.z.string().nullable(),
twitter_image: zod.z.string().nullable(),
twitter_title: zod.z.string().nullable(),
twitter_description: zod.z.string().nullable(),
members_support_address: zod.z.string(),
url: zod.z.string()
});
var baseTiersSchema = zod.z.object({
...ghostIdentitySchema.shape,
name: zod.z.string(),
description: zod.z.string().nullable(),
active: zod.z.boolean(),
type: zod.z.union([zod.z.literal("free"), zod.z.literal("paid")]),
welcome_page_url: zod.z.string().nullable(),
created_at: zod.z.string(),
updated_at: zod.z.string().nullable(),
stripe_prices: zod.z.array(zod.z.number()).optional().transform((v) => v?.length ? v : []),
monthly_price: zod.z.number().nullable().optional().transform((v) => v ? v : null),
yearly_price: zod.z.number().nullable().optional().transform((v) => v ? v : null),
benefits: zod.z.array(zod.z.string()).optional(),
visibility: ghostVisibilitySchema,
currency: zod.z.string().nullish(),
trial_days: zod.z.number().default(0)
});
var baseEmailSchema = zod.z.object({
id: zod.z.string(),
uuid: zod.z.string(),
status: zod.z.string(),
recipient_filter: zod.z.string(),
error: zod.z.string().nullish(),
error_data: zod.z.any().nullable(),
email_count: zod.z.number(),
delivered_count: zod.z.number(),
opened_count: zod.z.number(),
failed_count: zod.z.number(),
subject: zod.z.string(),
from: zod.z.string(),
reply_to: zod.z.string().nullable(),
source: zod.z.string(),
// lexical format
html: zod.z.string().nullable(),
plaintext: zod.z.string().nullable(),
track_opens: zod.z.boolean(),
submitted_at: zod.z.string(),
created_at: zod.z.string(),
updated_at: zod.z.string()
});
var baseOffersSchema = zod.z.object({
id: zod.z.string(),
name: zod.z.string({ description: "Internal name for an offer, must be unique" }).default(""),
code: zod.z.string({ description: "Shortcode for the offer, for example: https://yoursite.com/black-friday" }),
display_title: zod.z.string({ description: "Name displayed in the offer window" }).nullish(),
display_description: zod.z.string({ description: "Text displayed in the offer window" }).nullish(),
type: zod.z.union([zod.z.literal("percent"), zod.z.literal("fixed"), zod.z.literal("trial")]),
cadence: zod.z.union([zod.z.literal("month"), zod.z.literal("year")]),
amount: zod.z.number({
description: `Offer discount amount, as a percentage or fixed value as set in type.
Amount is always denoted by the smallest currency unit
(e.g., 100 cents instead of $1.00 in USD)`
}),
duration: zod.z.union([zod.z.literal("once"), zod.z.literal("forever"), zod.z.literal("repeating"), zod.z.literal("trial")], {
description: "once/forever/repeating. repeating duration is only available when cadence is month"
}),
duration_in_months: zod.z.number({ description: "Number of months offer should be repeated when duration is repeating" }).nullish(),
currency_restriction: zod.z.boolean({
description: "Denotes whether the offer `currency` is restricted. If so, changing the currency invalidates the offer"
}).nullish(),
currency: zod.z.string({
description: "fixed type offers only - specifies tier's currency as three letter ISO currency code"
}).nullish(),
status: zod.z.union([zod.z.literal("active"), zod.z.literal("archived")], {
description: "active or archived - denotes if the offer is active or archived"
}),
redemption_count: zod.z.number({ description: "Number of times the offer has been redeemed" }).nullish(),
tier: zod.z.object(
{
id: zod.z.string(),
name: zod.z.string().nullish()
},
{ description: "Tier on which offer is applied" }
)
});
var baseNewsletterSchema = zod.z.object({
...ghostIdentitySchema.shape,
name: zod.z.string({ description: "Public name for the newsletter" }),
description: zod.z.string({ description: "(nullable) Public description of the newsletter" }).nullish(),
sender_name: zod.z.string({ description: "(nullable) The sender name of the emails" }).nullish(),
sender_email: zod.z.string({ description: "(nullable) The email from which to send emails. Requires validation." }).nullish(),
sender_reply_to: zod.z.string({
description: "The reply-to email address for sent emails. Can be either newsletter (= use sender_email) or support (use support email from Portal settings)."
}),
status: zod.z.union([zod.z.literal("active"), zod.z.literal("archived")], {
description: "active or archived - denotes if the newsletter is active or archived"
}),
visibility: zod.z.union([zod.z.literal("public"), zod.z.literal("members")]),
subscribe_on_signup: zod.z.boolean({
description: "true/false. Whether members should automatically subscribe to this newsletter on signup"
}),
sort_order: zod.z.number({ description: "The order in which newsletters are displayed in the Portal" }),
header_image: zod.z.string({
description: "(nullable) Path to an image to show at the top of emails. Recommended size 1200x600"
}).nullish(),
show_header_icon: zod.z.boolean({ description: "true/false. Show the site icon in emails" }),
show_header_title: zod.z.boolean({ description: "true/false. Show the site name in emails" }),
title_font_category: zod.z.union([zod.z.literal("serif"), zod.z.literal("sans_serif")], {
description: "Title font style. Either serif or sans_serif"
}),
title_alignment: zod.z.string().nullish(),
show_feature_image: zod.z.boolean({ description: "true/false. Show the post's feature image in emails" }),
body_font_category: zod.z.union([zod.z.literal("serif"), zod.z.literal("sans_serif")], {
description: "Body font style. Either serif or sans_serif"
}),
footer_content: zod.z.string({
description: "(nullable) Extra information or legal text to show in the footer of emails. Should contain valid HTML."
}).nullish(),
show_badge: zod.z.boolean({
description: "true/false. Show you\u2019re a part of the indie publishing movement by adding a small Ghost badge in the footer"
}),
created_at: zod.z.string(),
updated_at: zod.z.string().nullish(),
show_header_name: zod.z.boolean({ description: "true/false. Show the newsletter name in emails" }),
uuid: zod.z.string()
});
var baseSubscriptionsSchema = zod.z.object({
id: zod.z.string({ description: "Stripe subscription ID sub_XXXX" }),
customer: zod.z.object(
{
id: zod.z.string(),
name: zod.z.string().nullable(),
email: zod.z.string()
},
{ description: "Stripe customer attached to the subscription" }
),
status: zod.z.string({ description: "Subscription status" }),
start_date: zod.z.string({ description: "Subscription start date" }),
default_payment_card_last4: zod.z.string({ description: "Last 4 digits of the card" }).nullable(),
cancel_at_period_end: zod.z.boolean({
description: "If the subscription should be canceled or renewed at period end"
}),
cancellation_reason: zod.z.string({ description: "Reason for subscription cancellation" }).nullable(),
current_period_end: zod.z.string({ description: "Subscription end date" }),
price: zod.z.object({
id: zod.z.string({ description: "Stripe price ID" }),
price_id: zod.z.string({ description: "Ghost price ID" }),
nickname: zod.z.string({ description: "Price nickname" }),
amount: zod.z.number({ description: "Price amount" }),
interval: zod.z.string({ description: "Price interval" }),
type: zod.z.string({ description: "Price type" }),
currency: zod.z.string({ description: "Price currency" })
}),
tier: baseTiersSchema.nullish(),
offer: baseOffersSchema.nullish()
});
// src/schemas/members.ts
var baseMembersSchema = zod.z.object({
id: zod.z.string(),
email: zod.z.string({ description: "The email address of the member" }),
name: zod.z.string({ description: "The name of the member" }).nullable(),
note: zod.z.string({ description: "(nullable) A note about the member" }).nullish(),
geolocation: zod.z.string({ description: "(nullable) The geolocation of the member" }).nullish(),
created_at: zod.z.string({ description: "The date and time the member was created" }),
updated_at: zod.z.string({ description: "(nullable) The date and time the member was last updated" }).nullish(),
labels: zod.z.array(
zod.z.object({
id: zod.z.string({ description: "The ID of the label" }),
name: zod.z.string({ description: "The name of the label" }),
slug: zod.z.string({ description: "The slug of the label" }),
created_at: zod.z.string({ description: "The date and time the label was created" }),
updated_at: zod.z.string({ description: "(nullable) The date and time the label was last updated" }).nullish()
}),
{ description: "The labels associated with the member" }
),
subscriptions: zod.z.array(baseSubscriptionsSchema, {
description: "The subscriptions associated with the member"
}),
avatar_image: zod.z.string({ description: "The URL of the member's avatar image" }),
email_count: zod.z.number({ description: "The number of emails sent to the member" }),
email_opened_count: zod.z.number({ description: "The number of emails opened by the member" }),
email_open_rate: zod.z.number({ description: "(nullable) The open rate of the member" }).nullish(),
status: zod.z.string({ description: "The status of the member" }),
last_seen_at: zod.z.string({ description: "(nullable) The date and time the member was last seen" }).nullish(),
newsletters: zod.z.array(baseNewsletterSchema)
});
var baseSiteSchema = zod.z.object({
title: zod.z.string(),
description: zod.z.string(),
logo: zod.z.string().nullable(),
version: zod.z.string(),
url: zod.z.string()
});
// src/fetchers/formats.ts
var contentFormats = ["html", "mobiledoc", "plaintext", "lexical"];
// src/fetchers/browse-fetcher.ts
var BrowseFetcher = class _BrowseFetcher {
constructor(resource, config, _params = { browseParams: {}, include: [], fields: {} }, httpClient) {
this.resource = resource;
this.config = config;
this._params = _params;
this.httpClient = httpClient;
this._urlParams = {};
this._urlSearchParams = void 0;
this._includeFields = [];
this._buildUrlParams();
}
/**
* Lets you choose output format for the content of Post and Pages resources
* The choices are html, mobiledoc or plaintext. It will transform the output of the fetcher to a new shape
* with the selected formats required.
*
* @param formats html, mobiledoc or plaintext
* @returns A new Fetcher with the fixed output shape and the formats specified
*/
formats(formats) {
const params = {
...this._params,
formats: Object.keys(formats).filter((key) => contentFormats.includes(key))
};
return new _BrowseFetcher(
this.resource,
{
schema: this.config.schema,
output: this.config.output.required(formats),
include: this.config.include
},
params,
this.httpClient
);
}
/**
* Let's you include special keys into the Ghost API Query to retrieve complimentary info
* The available keys are defined by the Resource include schema, will not care about unknown keys.
* Returns a new Fetcher with an Output shape modified with the include keys required.
*
* @param include Include specific keys from the include shape
* @returns A new Fetcher with the fixed output shape and the formats specified
*/
include(include) {
const params = {
...this._params,
include: Object.keys(this.config.include.parse(include))
};
return new _BrowseFetcher(
this.resource,
{
schema: this.config.schema,
output: this.config.output.required(include),
include: this.config.include
},
params,
this.httpClient
);
}
/**
* Let's you strip the output to only the specified keys of your choice that are in the config Schema
* Will not care about unknown keys and return a new Fetcher with an Output shape with only the selected keys.
*
* @param fields Any keys from the resource Schema
* @returns A new Fetcher with the fixed output shape having only the selected Fields
*/
fields(fields) {
const newOutput = this.config.output.pick(fields);
return new _BrowseFetcher(
this.resource,
{
schema: this.config.schema,
output: newOutput,
include: this.config.include
},
this._params,
this.httpClient
);
}
getResource() {
return this.resource;
}
getParams() {
return this._params;
}
getOutputFields() {
return this.config.output.keyof().options;
}
getURLSearchParams() {
return this._urlSearchParams;
}
getIncludes() {
return this._params?.include || [];
}
getFormats() {
return this._params?.formats || [];
}
_buildUrlParams() {
const inputKeys = this.config.schema.keyof().options;
const outputKeys = this.config.output.keyof().options;
this._urlParams = {
...this._urlBrowseParams()
};
if (inputKeys.length !== outputKeys.length && outputKeys.length > 0) {
this._urlParams.fields = outputKeys.join(",");
}
if (this._params.include && this._params.include.length > 0) {
this._urlParams.include = this._params.include.join(",");
}
if (this._params.formats && this._params.formats.length > 0) {
this._urlParams.formats = this._params.formats.join(",");
}
this._urlSearchParams = new URLSearchParams();
for (const [key, value] of Object.entries(this._urlParams)) {
this._urlSearchParams.append(key, value);
}
}
_urlBrowseParams() {
let urlBrowseParams = {};
if (this._params.browseParams === void 0)
return {};
const { limit, page, ...params } = this._params.browseParams;
urlBrowseParams = {
...params
};
if (limit) {
urlBrowseParams.limit = limit.toString();
}
if (page) {
urlBrowseParams.page = page.toString();
}
return urlBrowseParams;
}
_getResultSchema() {
return zod.z.discriminatedUnion("success", [
zod.z.object({
success: zod.z.literal(true),
meta: ghostMetaSchema,
data: zod.z.array(this.config.output)
}),
zod.z.object({
success: zod.z.literal(false),
errors: zod.z.array(
zod.z.object({
type: zod.z.string(),
message: zod.z.string()
})
)
})
]);
}
async fetch(options) {
const resultSchema = this._getResultSchema();
const result = await this.httpClient.fetch({
resource: this.resource,
searchParams: this._urlSearchParams,
options
});
let data = {};
if (result.errors) {
data.success = false;
data.errors = result.errors;
} else {
data = {
success: true,
meta: result.meta || {
pagination: {
pages: 0,
page: 0,
limit: 15,
total: 0,
prev: null,
next: null
}
},
data: result[this.resource]
};
}
return resultSchema.parse(data);
}
async paginate(options) {
if (!this._params.browseParams?.page) {
this._params.browseParams = {
...this._params.browseParams,
page: 1
};
this._buildUrlParams();
}
const resultSchema = this._getResultSchema();
const result = await this.httpClient.fetch({
resource: this.resource,
searchParams: this._urlSearchParams,
options
});
let data = {};
if (result.errors) {
data.success = false;
data.errors = result.errors;
} else {
data = {
success: true,
meta: result.meta || {
pagination: {
pages: 0,
page: 0,
limit: 15,
total: 0,
prev: null,
next: null
}
},
data: result[this.resource]
};
}
const response = {
current: resultSchema.parse(data),
next: void 0
};
if (response.current.success === false)
return response;
const { meta } = response.current;
if (meta.pagination.pages <= 1 || meta.pagination.page === meta.pagination.pages)
return response;
const params = {
...this._params,
browseParams: {
...this._params.browseParams,
page: meta.pagination.page + 1
}
};
const next = new _BrowseFetcher(this.resource, this.config, params, this.httpClient);
response.next = next;
return response;
}
};
var ReadFetcher = class _ReadFetcher {
constructor(resource, config, _params, httpClient) {
this.resource = resource;
this.config = config;
this._params = _params;
this.httpClient = httpClient;
this._urlParams = {};
this._urlSearchParams = void 0;
this._pathnameIdentity = void 0;
this._includeFields = [];
this._buildUrlParams();
}
/**
* Lets you choose output format for the content of Post and Pages resources
* The choices are html, mobiledoc or plaintext. It will transform the output of the fetcher to a new shape
* with the selected formats required.
*
* @param formats html, mobiledoc or plaintext
* @returns A new Fetcher with the fixed output shape and the formats specified
*/
formats(formats) {
const params = {
...this._params,
formats: Object.keys(formats).filter((key) => contentFormats.includes(key))
};
return new _ReadFetcher(
this.resource,
{
schema: this.config.schema,
output: this.config.output.required(formats),
include: this.config.include
},
params,
this.httpClient
);
}
/**
* Let's you include special keys into the Ghost API Query to retrieve complimentary info
* The available keys are defined by the Resource include schema, will not care about unknown keys.
* Returns a new Fetcher with an Output shape modified with the include keys required.
*
* @param include Include specific keys from the include shape
* @returns A new Fetcher with the fixed output shape and the formats specified
*/
include(include) {
const params = {
...this._params,
include: Object.keys(this.config.include.parse(include))
};
return new _ReadFetcher(
this.resource,
{
schema: this.config.schema,
output: this.config.output.required(include),
include: this.config.include
},
params,
this.httpClient
);
}
/**
* Let's you strip the output to only the specified keys of your choice that are in the config Schema
* Will not care about unknown keys and return a new Fetcher with an Output shape with only the selected keys.
*
* @param fields Any keys from the resource Schema
* @returns A new Fetcher with the fixed output shape having only the selected Fields
*/
fields(fields) {
const newOutput = this.config.output.pick(fields);
return new _ReadFetcher(
this.resource,
{
schema: this.config.schema,
output: newOutput,
include: this.config.include
},
this._params,
this.httpClient
);
}
getResource() {
return this.resource;
}
getParams() {
return this._params;
}
getOutputFields() {
return this.config.output.keyof().options;
}
getIncludes() {
return this._params?.include || [];
}
getFormats() {
return this._params?.formats || [];
}
_buildUrlParams() {
const inputKeys = this.config.schema.keyof().options;
const outputKeys = this.config.output.keyof().options;
if (inputKeys.length !== outputKeys.length && outputKeys.length > 0) {
this._urlParams.fields = outputKeys.join(",");
}
if (this._params.include && this._params.include.length > 0) {
this._urlParams.include = this._params.include.join(",");
}
if (this._params.formats && this._params.formats.length > 0) {
this._urlParams.formats = this._params.formats.join(",");
}
if (this._params.identity.id) {
this._pathnameIdentity = `${this._params.identity.id}`;
} else if (this._params.identity.slug) {
this._pathnameIdentity = `slug/${this._params.identity.slug}`;
} else if (this._params.identity.email) {
this._pathnameIdentity = `email/${this._params.identity.email}`;
} else {
throw new Error("Identity is not defined");
}
this._urlSearchParams = new URLSearchParams();
for (const [key, value] of Object.entries(this._urlParams)) {
this._urlSearchParams.append(key, value);
}
}
async fetch(options) {
const res = zod.z.discriminatedUnion("success", [
zod.z.object({
success: zod.z.literal(true),
data: this.config.output
}),
zod.z.object({
success: zod.z.literal(false),
errors: zod.z.array(
zod.z.object({
type: zod.z.string(),
message: zod.z.string()
})
)
})
]);
const result = await this.httpClient.fetch({
resource: this.resource,
pathnameIdentity: this._pathnameIdentity,
searchParams: this._urlSearchParams,
options
});
let data = {};
if (result.errors) {
data.success = false;
data.errors = result.errors;
} else {
data = {
success: true,
data: result[this.resource][0]
};
}
return res.parse(data);
}
};
var BasicFetcher = class {
constructor(resource, config, httpClient) {
this.resource = resource;
this.config = config;
this.httpClient = httpClient;
}
getResource() {
return this.resource;
}
async fetch(options) {
const res = zod.z.discriminatedUnion("success", [
zod.z.object({
success: zod.z.literal(true),
data: this.config.output
}),
zod.z.object({
success: zod.z.literal(false),
errors: zod.z.array(
zod.z.object({
type: zod.z.string(),
message: zod.z.string()
})
)
})
]);
const result = await this.httpClient.fetch({ options, resource: this.resource });
let data = {};
if (result.errors) {
data.success = false;
data.errors = result.errors;
} else {
data = {
success: true,
data: result[this.resource]
};
}
return res.parse(data);
}
};
var MutationFetcher = class {
constructor(resource, config, _params, _options, httpClient) {
this.resource = resource;
this.config = config;
this._params = _params;
this._options = _options;
this.httpClient = httpClient;
this._urlParams = {};
this._urlSearchParams = void 0;
this._pathnameIdentity = void 0;
this._buildUrlParams();
}
getResource() {
return this.resource;
}
getParams() {
return this._params;
}
_buildUrlParams() {
if (this._params) {
for (const [key, value] of Object.entries(this._params)) {
if (key !== "id") {
this._urlParams[key] = value;
}
}
}
this._urlSearchParams = new URLSearchParams();
if (this._params?.id) {
this._pathnameIdentity = `${this._params.id}`;
}
for (const [key, value] of Object.entries(this._urlParams)) {
this._urlSearchParams.append(key, value);
}
}
async submit() {
const schema = zod.z.discriminatedUnion("success", [
zod.z.object({
success: zod.z.literal(true),
data: this.config.output
}),
zod.z.object({
success: zod.z.literal(false),
errors: zod.z.array(
zod.z.object({
type: zod.z.string(),
message: zod.z.string(),
context: zod.z.string().nullish()
})
)
})
]);
const createData = {
[this.resource]: [this._options.body]
};
const response = await this.httpClient.fetch({
resource: this.resource,
searchParams: this._urlSearchParams,
pathnameIdentity: this._pathnameIdentity,
options: {
method: this._options.method,
body: JSON.stringify(createData)
}
});
let result = {};
if (response.errors) {
result.success = false;
result.errors = response.errors;
} else {
result = {
success: true,
data: response[this.resource][0]
};
}
return schema.parse(result);
}
};
var DeleteFetcher = class {
constructor(resource, _params, httpClient) {
this.resource = resource;
this._params = _params;
this.httpClient = httpClient;
this._pathnameIdentity = void 0;
this._buildPathnameIdentity();
}
getResource() {
return this.resource;
}
getParams() {
return this._params;
}
_buildPathnameIdentity() {
if (!this._params.id) {
throw new Error("Missing id in params");
}
this._pathnameIdentity = this._params.id;
}
async submit() {
const schema = zod.z.discriminatedUnion("success", [
zod.z.object({
success: zod.z.literal(true)
}),
zod.z.object({
success: zod.z.literal(false),
errors: zod.z.array(
zod.z.object({
type: zod.z.string(),
message: zod.z.string(),
context: zod.z.string().nullish()
})
)
})
]);
let result = {};
try {
const response = await this.httpClient.fetchRawResponse({
resource: this.resource,
pathnameIdentity: this._pathnameIdentity,
options: {
method: "DELETE"
}
});
if (response.status === 204) {
result = {
success: true
};
} else {
const res = await response.json();
if (res.errors) {
result.success = false;
result.errors = res.errors;
}
}
} catch (e) {
result = {
success: false,
errors: [
{
type: "FetchError",
message: e.toString()
}
]
};
}
return schema.parse(result);
}
};
var browseParamsSchema = zod.z.object({
order: zod.z.string().optional(),
limit: zod.z.union([
zod.z.literal("all"),
zod.z.number().refine((n) => n && n > 0 && n <= 15, {
message: "Limit must be between 1 and 15"
})
]).optional(),
page: zod.z.number().refine((n) => n && n >= 1, {
message: "Page must be greater than 1"
}).optional(),
filter: zod.z.string().optional()
});
var parseBrowseParams = (args, schema, includeSchema) => {
const keys = [
...schema.keyof().options,
...includeSchema && includeSchema.keyof().options || []
];
const augmentedSchema = browseParamsSchema.merge(
zod.z.object({
order: zod.z.string().superRefine((val, ctx) => {
const orderPredicates = val.split(",");
for (const orderPredicate of orderPredicates) {
const [field, direction] = orderPredicate.split(" ");
if (!keys.includes(field)) {
ctx.addIssue({
code: zod.z.ZodIssueCode.custom,
message: `Field "${field}" is not a valid field`,
fatal: true
});
}
if (direction && !(direction.toUpperCase() === "ASC" || direction.toUpperCase() === "DESC")) {
ctx.addIssue({
code: zod.z.ZodIssueCode.custom,
message: "Order direction must be ASC or DESC",
fatal: true
});
}
}
}).optional(),
filter: zod.z.string().superRefine((val, ctx) => {
const filterPredicates = val.replace(/ *\[[^)]*\] */g, "").split(/[+(,]+/);
for (const filterPredicate of filterPredicates) {
const field = filterPredicate.split(":")[0].split(".")[0];
if (!keys.includes(field)) {
ctx.addIssue({
code: zod.z.ZodIssueCode.custom,
message: `Field "${field}" is not a valid field`,
fatal: true
});
}
}
}).optional()
})
);
return augmentedSchema.parse(args);
};
// src/api-composer.ts
function isZodObject(schema) {
return schema.partial !== void 0;
}
var APIComposer = class {
constructor(resource, config, httpClient) {
this.resource = resource;
this.config = config;
this.httpClient = httpClient;
}
/**
* Browse function that accepts browse params order, filter, page and limit. Will return an instance
* of BrowseFetcher class.
*/
browse(options) {
return new BrowseFetcher(
this.resource,
{
schema: this.config.schema,
output: this.config.schema,
include: this.config.include
},
{
browseParams: options && parseBrowseParams(options, this.config.schema, this.config.include) || void 0
},
this.httpClient
);
}
/**
* Read function that accepts Identify fields like id, slug or email. Will return an instance
* of ReadFetcher class.
*/
read(options) {
return new ReadFetcher(
this.resource,
{
schema: this.config.schema,
output: this.config.schema,
include: this.config.include
},
{
identity: this.config.identitySchema.parse(options)
},
this.httpClient
);
}
async add(data, options) {
if (!this.config.createSchema) {
throw new Error("No createSchema defined");
}
const parsedData = this.config.createSchema.parse(data);
const parsedOptions = this.config.createOptionsSchema && options ? this.config.createOptionsSchema.parse(options) : void 0;
const fetcher = new MutationFetcher(
this.resource,
{
output: this.config.schema,
paramsShape: this.config.createOptionsSchema
},
parsedOptions,
{ method: "POST", body: parsedData },
this.httpClient
);
return fetcher.submit();
}
async edit(id, data, options) {
let updateSchema = this.config.updateSchema;
if (!this.config.updateSchema && this.config.createSchema && isZodObject(this.config.createSchema)) {
updateSchema = this.config.createSchema.partial();
}
if (!updateSchema) {
throw new Error("No updateSchema defined");
}
const cleanId = zod.z.string().nonempty().parse(id);
const parsedData = updateSchema.parse(data);
const parsedOptions = this.config.updateOptionsSchema && options ? this.config.updateOptionsSchema.parse(options) : {};
if (Object.keys(parsedData).length === 0) {
throw new Error("No data to edit");
}
const fetcher = new MutationFetcher(
this.resource,
{
output: this.config.schema,
paramsShape: this.config.updateOptionsSchema
},
{ id: cleanId, ...parsedOptions },
{ method: "PUT", body: parsedData },
this.httpClient
);
return fetcher.submit();
}
async delete(id) {
const cleanId = zod.z.string().nonempty().parse(id);
const fetcher = new DeleteFetcher(this.resource, { id: cleanId }, this.httpClient);
return fetcher.submit();
}
access(keys) {
const d = {};
keys.forEach((key) => {
d[key] = this[key].bind(this);
});
return d;
}
};
// src/helpers/fields.ts
var schemaWithPickedFields = (schema, fields) => {
return schema.pick(fields || {});
};
var HTTPClient = class {
constructor(config) {
this.config = config;
this._baseURL = void 0;
let prefixPath = new URL(config.url).pathname;
if (prefixPath.slice(-1) === "/") {
prefixPath = prefixPath.slice(0, -1);
}
this._baseURL = new URL(`${prefixPath}/ghost/api/${config.endpoint}/`, config.url);
}
get baseURL() {
return this._baseURL;
}
get jwt() {
return this._jwt;
}
async generateJWT(key) {
const [id, _secret] = key.split(":");
this._jwtExpiresAt = Date.now() + 5 * 60 * 1e3;
return new jose.SignJWT({}).setProtectedHeader({ kid: id, alg: "HS256" }).setExpirationTime("5m").setIssuedAt().setAudience("/admin/").sign(
Uint8Array.from(_secret.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)))
);
}
async genHeaders() {
const headers = {
"Content-Type": "application/json",
"Accept-Version": this.config.version
};
if (this.config.endpoint === "admin") {
if (this._jwt === void 0 || this._jwtExpiresAt === void 0 || this._jwtExpiresAt < Date.now()) {
this._jwt = await this.generateJWT(this.config.key);
}
headers["Authorization"] = `Ghost ${this.jwt}`;
}
return headers;
}
async fetch({
resource,
searchParams,
options,
pathnameIdentity
}) {
if (this._baseURL === void 0)
throw new Error("URL is undefined");
let path = `${resource}/`;
if (pathnameIdentity !== void 0) {
path += `${pathnameIdentity}/`;
}
const url = new URL(path, this._baseURL);
if (searchParams !== void 0) {
for (const [key, value] of searchParams.entries()) {
url.searchParams.append(key, value);
}
}
if (this.config.endpoint === "content") {
url.searchParams.append("key", this.config.key);
}
let result = void 0;
const headers = await this.genHeaders();
try {
result = await (await fetch(url.toString(), {
...options,
headers
})).json();
} catch (e) {
return {
status: "error",
errors: [
{
type: "FetchError",
message: e.toString()
}
]
};
}
return result;
}
async fetchRawResponse({
resource,
searchParams,
options,
pathnameIdentity
}) {
if (this._baseURL === void 0)
throw new Error("URL is undefined");
this._baseURL.pathname += `${resource}/`;
if (pathnameIdentity !== void 0) {
this._baseURL.pathname += `${pathnameIdentity}/`;
}
if (searchParams !== void 0) {
for (const [key, value] of searchParams.entries()) {
this._baseURL.searchParams.append(key, value);
}
}
if (this.config.endpoint === "content") {
this._baseURL.searchParams.append("key", this.config.key);
}
const headers = await this.genHeaders();
return await fetch(this._baseURL.toString(), {
...options,
headers
});
}
};
exports.APIComposer = APIComposer;
exports.BasicFetcher = BasicFetcher;
exports.BrowseFetcher = BrowseFetcher;
exports.DeleteFetcher = DeleteFetcher;
exports.HTTPClient = HTTPClient;
exports.MutationFetcher = MutationFetcher;
exports.ReadFetcher = ReadFetcher;
exports.adminAPICredentialsSchema = adminAPICredentialsSchema;
exports.apiVersionsSchema = apiVersionsSchema;
exports.baseAuthorsSchema = baseAuthorsSchema;
exports.baseEmailSchema = baseEmailSchema;
exports.baseMembersSchema = baseMembersSchema;
exports.baseNewsletterSchema = baseNewsletterSchema;
exports.baseOffersSchema = baseOffersSchema;
exports.basePagesSchema = basePagesSchema;
exports.basePostsSchema = basePostsSchema;
exports.baseSettingsSchema = baseSettingsSchema;
exports.baseSiteSchema = baseSiteSchema;
exports.baseTagsSchema = baseTagsSchema;
exports.baseTiersSchema = baseTiersSchema;
exports.browseParamsSchema = browseParamsSchema;
exports.contentAPICredentialsSchema = contentAPICredentialsSchema;
exports.emailOrIdSchema = emailOrIdSchema;
exports.ghostCodeInjectionSchema = ghostCodeInjectionSchema;
exports.ghostExcerptSchema = ghostExcerptSchema;
exports.ghostFacebookSchema = ghostFacebookSchema;
exports.ghostIdentityInputSchema = ghostIdentityInputSchema;
exports.ghostIdentitySchema = ghostIdentitySchema;
exports.ghostMetaSchema = ghostMetaSchema;
exports.ghostMetadataSchema = ghostMetadataSchema;
exports.ghostSocialMediaSchema = ghostSocialMediaSchema;
exports.ghostTwitterSchema = ghostTwitterSchema;
exports.ghostVisibilitySchema = ghostVisibilitySchema;
exports.identitySchema = identitySchema;
exports.parseBrowseParams = parseBrowseParams;
exports.schemaWithPickedFields = schemaWithPickedFields;
exports.slugOrIdSchema = slugOrIdSchema;
//# sourceMappingURL=out.js.map
//# sourceMappingURL=index.js.map