@stephensauceda/apple-news 1.2.0 → 2.0.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/README.md CHANGED
@@ -94,10 +94,23 @@ await client.deleteArticle({ articleId: 'article-id' })
94
94
  ### searchArticles
95
95
 
96
96
  Provide exactly one of channelId or sectionId.
97
+ Search query parameters follow Apple News API names. Omitted parameters are not
98
+ sent, allowing Apple News to apply its documented defaults. `pageSize` must be
99
+ an integer from 1 to 100; `pageToken` is an opaque pagination token; `fromDate`
100
+ and `toDate` use ISO 8601; `sortDir` is `ASC` or `DESC`. Additional query
101
+ options are passed through for forward compatibility. The returned search
102
+ response preserves the full API response, including its `articles`, `links`,
103
+ and `meta` fields when provided.
104
+ The optional `date` is the HHMAC request-signing timestamp, not a search filter.
97
105
 
98
106
  ```js
99
- await client.searchArticles({ channelId: 'channel-id', limit: 25 })
100
- await client.searchArticles({ sectionId: 'section-id', offset: 50 })
107
+ await client.searchArticles({ channelId: 'channel-id', pageSize: 25 })
108
+ await client.searchArticles({
109
+ sectionId: 'section-id',
110
+ fromDate: '2026-01-01T00:00:00Z',
111
+ toDate: '2026-02-01T00:00:00Z',
112
+ sortDir: 'ASC'
113
+ })
101
114
  ```
102
115
 
103
116
  ### createArticle
@@ -149,6 +162,7 @@ await client.promoteArticles({ sectionId: 'section-id', articleIds: [] })
149
162
  ### updateArticle
150
163
 
151
164
  revision is required.
165
+ Optional metadata is sent only when provided. To publish an article immediately, pass `isPreview: false`.
152
166
 
153
167
  ```js
154
168
  await client.updateArticle({
package/dist/index.js CHANGED
@@ -162,6 +162,9 @@ async function requestSigned(options) {
162
162
  if (parsedBody === null) {
163
163
  return null;
164
164
  }
165
+ if (options.returnFullResponse) {
166
+ return parsedBody;
167
+ }
165
168
  return unwrapData(parsedBody);
166
169
  }
167
170
 
@@ -218,7 +221,8 @@ function buildArticleMultipartBody(input) {
218
221
  boundary,
219
222
  "article.json",
220
223
  Buffer.from(JSON.stringify(input.article), "utf8"),
221
- "application/json"
224
+ "application/json",
225
+ "article.json"
222
226
  )
223
227
  );
224
228
  parts.push(
@@ -264,11 +268,22 @@ function assertId(value, name) {
264
268
  }
265
269
  }
266
270
  function buildMetadata(options, host, includeRevision = false) {
267
- const metadata = {
271
+ const metadata = includeRevision ? {} : {
268
272
  isPreview: options.isPreview ?? true,
269
273
  isSponsored: options.isSponsored ?? false,
270
274
  isPaid: options.isPaid ?? false
271
275
  };
276
+ if (includeRevision) {
277
+ if (options.isPreview !== void 0) {
278
+ metadata.isPreview = options.isPreview;
279
+ }
280
+ if (options.isSponsored !== void 0) {
281
+ metadata.isSponsored = options.isSponsored;
282
+ }
283
+ if (options.isPaid !== void 0) {
284
+ metadata.isPaid = options.isPaid;
285
+ }
286
+ }
272
287
  if (options.sections !== void 0) {
273
288
  metadata.links = {
274
289
  sections: options.sections.map(
@@ -369,22 +384,32 @@ var AppleNewsClient = class {
369
384
  * @param {Record<string, unknown>} options
370
385
  * @param {string} [options.channelId]
371
386
  * @param {string} [options.sectionId]
372
- * @param {string|Date} [options.date]
387
+ * @param {number} [options.pageSize] An integer from 1 to 100
388
+ * @param {string} [options.pageToken] Opaque token from a previous response
389
+ * @param {string} [options.fromDate] ISO 8601 lower bound
390
+ * @param {string} [options.toDate] ISO 8601 upper bound
391
+ * @param {'ASC'|'DESC'} [options.sortDir]
392
+ * @param {string|Date} [options.date] HHMAC signing timestamp, not a filter
393
+ * @returns {Promise<Record<string, unknown>>} Full search response, including pagination metadata
373
394
  */
374
395
  async searchArticles(options) {
375
- const hasChannelId = typeof options?.channelId === "string" && options.channelId.length > 0;
376
- const hasSectionId = typeof options?.sectionId === "string" && options.sectionId.length > 0;
377
- if (!hasChannelId && !hasSectionId) {
396
+ if (!options?.channelId && !options?.sectionId) {
378
397
  throw new TypeError(
379
398
  "searchArticles requires either channelId or sectionId"
380
399
  );
381
400
  }
382
- if (hasChannelId && hasSectionId) {
401
+ if (options.channelId && options.sectionId) {
383
402
  throw new TypeError(
384
403
  "searchArticles accepts either channelId or sectionId, not both"
385
404
  );
386
405
  }
387
- const endpoint = hasChannelId ? `/channels/${options.channelId}/articles` : `/sections/${options.sectionId}/articles`;
406
+ if (options.pageSize !== void 0 && (!Number.isInteger(options.pageSize) || options.pageSize < 1 || options.pageSize > 100)) {
407
+ throw new TypeError("pageSize must be an integer between 1 and 100");
408
+ }
409
+ if (options.sortDir !== void 0 && options.sortDir !== "ASC" && options.sortDir !== "DESC") {
410
+ throw new TypeError("sortDir must be either ASC or DESC");
411
+ }
412
+ const endpoint = options.channelId ? `/channels/${options.channelId}/articles` : `/sections/${options.sectionId}/articles`;
388
413
  const query = { ...options };
389
414
  const date = query.date;
390
415
  delete query.channelId;
@@ -392,7 +417,8 @@ var AppleNewsClient = class {
392
417
  delete query.date;
393
418
  return this.#request("GET", endpoint, {
394
419
  date,
395
- query
420
+ query,
421
+ returnFullResponse: true
396
422
  });
397
423
  }
398
424
  /**
@@ -426,9 +452,9 @@ var AppleNewsClient = class {
426
452
  * @param {string} options.revision
427
453
  * @param {Record<string, unknown>} options.article
428
454
  * @param {Record<string, ArticleBundleFile>} [options.bundleFiles]
429
- * @param {boolean} [options.isPreview=true]
430
- * @param {boolean} [options.isSponsored=false]
431
- * @param {boolean} [options.isPaid=false]
455
+ * @param {boolean} [options.isPreview]
456
+ * @param {boolean} [options.isSponsored]
457
+ * @param {boolean} [options.isPaid]
432
458
  * @param {string[]} [options.sections]
433
459
  * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]
434
460
  * @param {string|Date} [options.date]
@@ -492,6 +518,7 @@ var AppleNewsClient = class {
492
518
  * @param {Record<string, string|number|boolean|undefined>} [options.query]
493
519
  * @param {string} [options.contentType]
494
520
  * @param {string|Buffer|Uint8Array|null} [options.body]
521
+ * @param {boolean} [options.returnFullResponse]
495
522
  */
496
523
  async #request(method, endpoint, options = {}) {
497
524
  return requestSigned({
@@ -503,7 +530,8 @@ var AppleNewsClient = class {
503
530
  date: options.date,
504
531
  query: options.query,
505
532
  contentType: options.contentType,
506
- body: options.body
533
+ body: options.body,
534
+ returnFullResponse: options.returnFullResponse
507
535
  });
508
536
  }
509
537
  };
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/auth.js", "../src/request.js", "../src/multipart.js", "../src/client.js", "../src/helpers/fetchBundleFiles.js"],
4
- "sourcesContent": ["import { createHmac } from 'node:crypto'\n\n/**\n * @param {Date} date\n * @returns {string}\n */\nexport function formatAppleDate(date) {\n const iso = date.toISOString()\n return iso.replace(/\\.\\d{3}Z$/, 'Z')\n}\n\n/**\n * @param {string|Uint8Array|Buffer|undefined|null} value\n * @returns {Buffer}\n */\nfunction toBuffer(value) {\n if (value == null) {\n return Buffer.alloc(0)\n }\n\n if (Buffer.isBuffer(value)) {\n return value\n }\n\n if (value instanceof Uint8Array) {\n return Buffer.from(value)\n }\n\n return Buffer.from(String(value), 'utf8')\n}\n\n/**\n * @typedef BuildCanonicalRequestInput\n * @property {string} method\n * @property {string} url\n * @property {string} date\n * @property {string} [contentType]\n * @property {string|Uint8Array|Buffer|undefined|null} [body]\n */\n\n/**\n * Build canonical payload for Apple HHMAC signing.\n *\n * @param {BuildCanonicalRequestInput} input\n * @returns {Buffer}\n */\nexport function buildCanonicalRequest(input) {\n const method = input.method.toUpperCase()\n const contentType = input.contentType ?? ''\n const prefix = `${method}${input.url}${input.date}${contentType}`\n const prefixBuffer = Buffer.from(prefix, 'utf8')\n const bodyBuffer = toBuffer(input.body)\n\n if (bodyBuffer.length === 0) {\n return prefixBuffer\n }\n\n return Buffer.concat([prefixBuffer, bodyBuffer])\n}\n\n/**\n * @param {string} apiSecret Base64 encoded Apple News API secret\n * @param {Buffer} canonicalPayload\n * @returns {string}\n */\nexport function signCanonicalRequest(apiSecret, canonicalPayload) {\n const key = Buffer.from(apiSecret, 'base64')\n\n return createHmac('sha256', key).update(canonicalPayload).digest('base64')\n}\n\n/**\n * @param {{ apiId: string, signature: string, date: string }} input\n * @returns {string}\n */\nexport function buildAuthorizationHeader(input) {\n return `HHMAC; key=\"${input.apiId}\"; signature=\"${input.signature}\"; date=\"${input.date}\"`\n}\n\n/**\n * @typedef CreateSignedHeadersInput\n * @property {string} apiId\n * @property {string} apiSecret\n * @property {string} method\n * @property {string} url\n * @property {string|Date} [date]\n * @property {string} [contentType]\n * @property {string|Uint8Array|Buffer|undefined|null} [body]\n */\n\n/**\n * @param {CreateSignedHeadersInput} input\n * @returns {{ headers: Record<string, string>, date: string, signature: string, canonicalPayload: Buffer }}\n */\nexport function createSignedHeaders(input) {\n const date =\n typeof input.date === 'string'\n ? input.date\n : formatAppleDate(input.date ?? new Date())\n const contentType = input.contentType ?? ''\n\n const canonicalPayload = buildCanonicalRequest({\n method: input.method,\n url: input.url,\n date,\n contentType,\n body: input.body\n })\n\n const signature = signCanonicalRequest(input.apiSecret, canonicalPayload)\n const authorization = buildAuthorizationHeader({\n apiId: input.apiId,\n signature,\n date\n })\n\n const headers = {\n Accept: 'application/json',\n Authorization: authorization\n }\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n return {\n headers,\n date,\n signature,\n canonicalPayload\n }\n}\n", "import { createSignedHeaders } from './auth.js'\n\n/**\n * @typedef RequestOptions\n * @property {string} apiId\n * @property {string} apiSecret\n * @property {string} method\n * @property {string} endpoint\n * @property {string} [host]\n * @property {Record<string, string | number | boolean | undefined>} [query]\n * @property {string} [contentType]\n * @property {string|Buffer|Uint8Array|null} [body]\n * @property {string|Date} [date]\n */\n\nexport class AppleNewsApiError extends Error {\n /**\n * @param {string} message\n * @param {Object} details\n * @param {number} details.status\n * @param {string} details.method\n * @param {string} details.url\n * @param {unknown[]} [details.apiErrors]\n * @param {unknown} [details.responseBody]\n */\n constructor(message, details) {\n super(message)\n this.name = 'AppleNewsApiError'\n this.status = details.status\n this.method = details.method\n this.url = details.url\n this.apiErrors = details.apiErrors\n this.responseBody = details.responseBody\n }\n}\n\n/**\n * @param {string} host\n * @param {string} endpoint\n * @param {Record<string, string | number | boolean | undefined>} [query]\n * @returns {string}\n */\nexport function buildRequestUrl(host, endpoint, query) {\n const url = new URL(`https://${host}${endpoint}`)\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) {\n continue\n }\n\n url.searchParams.set(key, String(value))\n }\n }\n\n return url.toString()\n}\n\n/**\n * @param {unknown} value\n * @returns {value is Record<string, unknown>}\n */\nfunction isObject(value) {\n return value !== null && typeof value === 'object'\n}\n\n/**\n * @param {unknown} parsed\n * @returns {unknown[]|undefined}\n */\nfunction getApiErrors(parsed) {\n if (!isObject(parsed)) {\n return undefined\n }\n\n const maybeErrors = parsed.errors\n if (!Array.isArray(maybeErrors)) {\n return undefined\n }\n\n return maybeErrors\n}\n\n/**\n * @param {unknown} parsed\n * @returns {unknown}\n */\nfunction unwrapData(parsed) {\n if (!isObject(parsed)) {\n return parsed\n }\n\n if ('data' in parsed) {\n return parsed.data\n }\n\n return parsed\n}\n\n/**\n * Execute one signed Apple News API request.\n *\n * @param {RequestOptions} options\n * @returns {Promise<unknown>}\n */\nexport async function requestSigned(options) {\n const host = options.host ?? 'news-api.apple.com'\n\n const url = buildRequestUrl(host, options.endpoint, options.query)\n const signed = createSignedHeaders({\n apiId: options.apiId,\n apiSecret: options.apiSecret,\n method: options.method,\n url,\n date: options.date,\n contentType: options.contentType,\n body: options.body\n })\n\n const response = await fetch(url, {\n method: options.method,\n headers: signed.headers,\n body: options.body ?? undefined\n })\n\n const rawBody = await response.text()\n let parsedBody = null\n\n if (rawBody.length > 0) {\n try {\n parsedBody = JSON.parse(rawBody)\n } catch {\n parsedBody = rawBody\n }\n }\n\n if (!response.ok) {\n const apiErrors = getApiErrors(parsedBody)\n throw new AppleNewsApiError(\n `${options.method.toUpperCase()} ${options.endpoint} failed with status ${response.status}`,\n {\n status: response.status,\n method: options.method.toUpperCase(),\n url,\n apiErrors,\n responseBody: parsedBody\n }\n )\n }\n\n if (parsedBody === null) {\n return null\n }\n\n return unwrapData(parsedBody)\n}\n", "const CRLF = '\\r\\n'\n\n/**\n * @typedef BundleFile\n * @property {Buffer|Uint8Array|string} data\n * @property {string} [mimeType]\n */\n\n/**\n * @param {Buffer|Uint8Array|string} data\n * @returns {Buffer}\n */\nfunction toBuffer(data) {\n if (Buffer.isBuffer(data)) {\n return data\n }\n\n if (data instanceof Uint8Array) {\n return Buffer.from(data)\n }\n\n return Buffer.from(String(data), 'utf8')\n}\n\n/**\n * @param {string} boundary\n * @param {string} name\n * @param {Buffer} value\n * @param {string} contentType\n * @param {string} [filename]\n * @returns {Buffer}\n */\nfunction buildPart(boundary, name, value, contentType, filename) {\n const lines = [`--${boundary}`]\n\n if (filename) {\n lines.push(\n `Content-Disposition: form-data; name=\"${name}\"; filename=\"${filename}\"`\n )\n } else {\n lines.push(`Content-Disposition: form-data; name=\"${name}\"`)\n }\n\n lines.push(`Content-Type: ${contentType}`)\n lines.push('')\n\n return Buffer.concat([\n Buffer.from(lines.join(CRLF) + CRLF, 'utf8'),\n value,\n Buffer.from(CRLF, 'utf8')\n ])\n}\n\n/**\n * @param {Record<string, BundleFile>|undefined} bundleFiles\n */\nfunction validateBundleFiles(bundleFiles) {\n if (!bundleFiles) {\n return\n }\n\n for (const name of Object.keys(bundleFiles)) {\n if (name === 'article.json' || name === 'metadata') {\n throw new TypeError(\n 'bundleFiles cannot contain reserved names: article.json or metadata'\n )\n }\n }\n}\n\n/**\n * @param {Object} input\n * @param {Record<string, unknown>} input.article\n * @param {Record<string, unknown>} [input.metadata]\n * @param {Record<string, BundleFile>} [input.bundleFiles]\n * @param {string} [input.boundary]\n * @returns {{ contentType: string, body: Buffer }}\n */\nexport function buildArticleMultipartBody(input) {\n if (!input.article || typeof input.article !== 'object') {\n throw new TypeError('article is required and must be an object')\n }\n\n validateBundleFiles(input.bundleFiles)\n\n const boundary = input.boundary ?? `apple-news-${Date.now().toString(16)}`\n const metadata = input.metadata ?? {}\n\n const parts = []\n parts.push(\n buildPart(\n boundary,\n 'article.json',\n Buffer.from(JSON.stringify(input.article), 'utf8'),\n 'application/json'\n )\n )\n\n parts.push(\n buildPart(\n boundary,\n 'metadata',\n Buffer.from(JSON.stringify({ data: metadata }), 'utf8'),\n 'application/json'\n )\n )\n\n if (input.bundleFiles) {\n let index = 0\n for (const [filename, file] of Object.entries(input.bundleFiles)) {\n const fieldName = `file${index}`\n index += 1\n parts.push(\n buildPart(\n boundary,\n fieldName,\n toBuffer(file.data),\n file.mimeType ?? 'application/octet-stream',\n filename\n )\n )\n }\n }\n\n parts.push(Buffer.from(`--${boundary}--${CRLF}`, 'utf8'))\n\n return {\n contentType: `multipart/form-data; boundary=${boundary}`,\n body: Buffer.concat(parts)\n }\n}\n", "import { requestSigned } from './request.js'\nimport { buildArticleMultipartBody } from './multipart.js'\n\n/**\n * @typedef AppleNewsClientConfig\n * @property {string} apiId\n * @property {string} apiSecret\n * @property {string} [host]\n */\n\nfunction assertRequired(value, name) {\n if (!value || typeof value !== 'string') {\n throw new TypeError(`${name} is required and must be a non-empty string`)\n }\n}\n\nfunction assertId(value, name) {\n if (!value || typeof value !== 'string') {\n throw new TypeError(`${name} is required and must be a non-empty string`)\n }\n}\n\n/**\n * @typedef {Object} ArticleBundleFile\n * @property {Buffer|Uint8Array|string} data\n * @property {string} [mimeType]\n */\n\n/**\n * @param {Object} options\n * @param {boolean} [options.isPreview=true]\n * @param {boolean} [options.isSponsored=false]\n * @param {boolean} [options.isPaid=false]\n * @param {string[]} [options.sections]\n * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]\n * @param {string} [options.revision]\n * @param {string} host\n * @param {boolean} includeRevision\n */\nfunction buildMetadata(options, host, includeRevision = false) {\n const metadata = {\n isPreview: options.isPreview ?? true,\n isSponsored: options.isSponsored ?? false,\n isPaid: options.isPaid ?? false\n }\n\n if (options.sections !== undefined) {\n metadata.links = {\n sections: options.sections.map(\n (sectionId) =>\n `https://${host}/sections/${encodeURIComponent(sectionId)}`\n )\n }\n }\n\n if (options.maturityRating !== undefined) {\n metadata.maturityRating = options.maturityRating\n }\n\n if (includeRevision) {\n metadata.revision = options.revision\n }\n\n return metadata\n}\n\n/**\n * @typedef {Object} SharedOptions\n * @property {string|Date} [date]\n */\n\n/**\n * @param {Record<string, unknown>|undefined} options\n * @returns {SharedOptions}\n */\nfunction getSharedOptions(options) {\n return {\n date: options?.date\n }\n}\n\nexport class AppleNewsClient {\n /**\n * @param {AppleNewsClientConfig} config\n */\n constructor(config) {\n assertRequired(config?.apiId, 'apiId')\n assertRequired(config?.apiSecret, 'apiSecret')\n\n this.apiId = config.apiId\n this.apiSecret = config.apiSecret\n this.host = config.host ?? 'news-api.apple.com'\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {string|Date} [options.date]\n */\n async readChannel(options) {\n assertId(options?.channelId, 'channelId')\n return this.#request(\n 'GET',\n `/channels/${options.channelId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {string|Date} [options.date]\n */\n async listSections(options) {\n assertId(options?.channelId, 'channelId')\n return this.#request(\n 'GET',\n `/channels/${options.channelId}/sections`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.sectionId\n * @param {string|Date} [options.date]\n */\n async readSection(options) {\n assertId(options?.sectionId, 'sectionId')\n return this.#request(\n 'GET',\n `/sections/${options.sectionId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.articleId\n * @param {string|Date} [options.date]\n */\n async readArticle(options) {\n assertId(options?.articleId, 'articleId')\n return this.#request(\n 'GET',\n `/articles/${options.articleId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.articleId\n * @param {string|Date} [options.date]\n */\n async deleteArticle(options) {\n assertId(options?.articleId, 'articleId')\n return this.#request(\n 'DELETE',\n `/articles/${options.articleId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Record<string, unknown>} options\n * @param {string} [options.channelId]\n * @param {string} [options.sectionId]\n * @param {string|Date} [options.date]\n */\n async searchArticles(options) {\n const hasChannelId =\n typeof options?.channelId === 'string' && options.channelId.length > 0\n const hasSectionId =\n typeof options?.sectionId === 'string' && options.sectionId.length > 0\n\n if (!hasChannelId && !hasSectionId) {\n throw new TypeError(\n 'searchArticles requires either channelId or sectionId'\n )\n }\n\n if (hasChannelId && hasSectionId) {\n throw new TypeError(\n 'searchArticles accepts either channelId or sectionId, not both'\n )\n }\n\n const endpoint = hasChannelId\n ? `/channels/${options.channelId}/articles`\n : `/sections/${options.sectionId}/articles`\n\n const query = { ...options }\n const date = query.date\n delete query.channelId\n delete query.sectionId\n delete query.date\n\n return this.#request('GET', endpoint, {\n date,\n query\n })\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {Record<string, unknown>} options.article\n * @param {Record<string, ArticleBundleFile>} [options.bundleFiles]\n * @param {boolean} [options.isPreview=true]\n * @param {boolean} [options.isSponsored=false]\n * @param {boolean} [options.isPaid=false]\n * @param {string[]} [options.sections]\n * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]\n * @param {string|Date} [options.date]\n */\n async createArticle(options) {\n assertId(options?.channelId, 'channelId')\n\n const multipart = buildArticleMultipartBody({\n article: options.article,\n metadata: buildMetadata(options, this.host),\n bundleFiles: options.bundleFiles\n })\n\n return this.#request('POST', `/channels/${options.channelId}/articles`, {\n date: options.date,\n contentType: multipart.contentType,\n body: multipart.body\n })\n }\n\n /**\n * @param {Object} options\n * @param {string} options.articleId\n * @param {string} options.revision\n * @param {Record<string, unknown>} options.article\n * @param {Record<string, ArticleBundleFile>} [options.bundleFiles]\n * @param {boolean} [options.isPreview=true]\n * @param {boolean} [options.isSponsored=false]\n * @param {boolean} [options.isPaid=false]\n * @param {string[]} [options.sections]\n * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]\n * @param {string|Date} [options.date]\n */\n async updateArticle(options) {\n assertId(options?.articleId, 'articleId')\n assertId(options?.revision, 'revision')\n\n const multipart = buildArticleMultipartBody({\n article: options.article,\n metadata: buildMetadata(options, this.host, true),\n bundleFiles: options.bundleFiles\n })\n\n return this.#request('POST', `/articles/${options.articleId}`, {\n date: options.date,\n contentType: multipart.contentType,\n body: multipart.body\n })\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {string|Date} [options.date]\n */\n async readChannelQuota(options) {\n assertId(options?.channelId, 'channelId')\n return this.#request(\n 'GET',\n `/channels/${options.channelId}/quota`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.sectionId\n * @param {string[]} options.articleIds\n * @param {string|Date} [options.date]\n */\n async promoteArticles(options) {\n assertId(options?.sectionId, 'sectionId')\n\n if (!Array.isArray(options?.articleIds)) {\n throw new TypeError('articleIds is required and must be an array')\n }\n\n const body = JSON.stringify({\n data: { promotedArticles: options.articleIds }\n })\n\n return this.#request(\n 'POST',\n `/sections/${options.sectionId}/promotedArticles`,\n {\n date: options.date,\n contentType: 'application/json',\n body\n }\n )\n }\n\n /**\n * @param {string} method\n * @param {string} endpoint\n * @param {Object} [options={}]\n * @param {string|Date} [options.date]\n * @param {Record<string, string|number|boolean|undefined>} [options.query]\n * @param {string} [options.contentType]\n * @param {string|Buffer|Uint8Array|null} [options.body]\n */\n async #request(method, endpoint, options = {}) {\n return requestSigned({\n apiId: this.apiId,\n apiSecret: this.apiSecret,\n host: this.host,\n method,\n endpoint,\n date: options.date,\n query: options.query,\n contentType: options.contentType,\n body: options.body\n })\n }\n}\n", "/**\n * @typedef BundleFetchResult\n * @property {Buffer} data\n * @property {string} mimeType\n */\n\n/**\n * @param {Record<string, string>} urlMap\n * @returns {Promise<Record<string, BundleFetchResult>>}\n */\nexport async function fetchBundleFiles(urlMap) {\n const result = {}\n\n for (const [filename, url] of Object.entries(urlMap)) {\n const response = await fetch(url)\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch bundle file ${filename} from ${url}: ${response.status}`\n )\n }\n\n const arrayBuffer = await response.arrayBuffer()\n const data = Buffer.from(arrayBuffer)\n const mimeType =\n response.headers.get('content-type') ?? 'application/octet-stream'\n\n result[filename] = {\n data,\n mimeType\n }\n }\n\n return result\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createHmac } from 'node:crypto'\n\n/**\n * @param {Date} date\n * @returns {string}\n */\nexport function formatAppleDate(date) {\n const iso = date.toISOString()\n return iso.replace(/\\.\\d{3}Z$/, 'Z')\n}\n\n/**\n * @param {string|Uint8Array|Buffer|undefined|null} value\n * @returns {Buffer}\n */\nfunction toBuffer(value) {\n if (value == null) {\n return Buffer.alloc(0)\n }\n\n if (Buffer.isBuffer(value)) {\n return value\n }\n\n if (value instanceof Uint8Array) {\n return Buffer.from(value)\n }\n\n return Buffer.from(String(value), 'utf8')\n}\n\n/**\n * @typedef BuildCanonicalRequestInput\n * @property {string} method\n * @property {string} url\n * @property {string} date\n * @property {string} [contentType]\n * @property {string|Uint8Array|Buffer|undefined|null} [body]\n */\n\n/**\n * Build canonical payload for Apple HHMAC signing.\n *\n * @param {BuildCanonicalRequestInput} input\n * @returns {Buffer}\n */\nexport function buildCanonicalRequest(input) {\n const method = input.method.toUpperCase()\n const contentType = input.contentType ?? ''\n const prefix = `${method}${input.url}${input.date}${contentType}`\n const prefixBuffer = Buffer.from(prefix, 'utf8')\n const bodyBuffer = toBuffer(input.body)\n\n if (bodyBuffer.length === 0) {\n return prefixBuffer\n }\n\n return Buffer.concat([prefixBuffer, bodyBuffer])\n}\n\n/**\n * @param {string} apiSecret Base64 encoded Apple News API secret\n * @param {Buffer} canonicalPayload\n * @returns {string}\n */\nexport function signCanonicalRequest(apiSecret, canonicalPayload) {\n const key = Buffer.from(apiSecret, 'base64')\n\n return createHmac('sha256', key).update(canonicalPayload).digest('base64')\n}\n\n/**\n * @param {{ apiId: string, signature: string, date: string }} input\n * @returns {string}\n */\nexport function buildAuthorizationHeader(input) {\n return `HHMAC; key=\"${input.apiId}\"; signature=\"${input.signature}\"; date=\"${input.date}\"`\n}\n\n/**\n * @typedef CreateSignedHeadersInput\n * @property {string} apiId\n * @property {string} apiSecret\n * @property {string} method\n * @property {string} url\n * @property {string|Date} [date]\n * @property {string} [contentType]\n * @property {string|Uint8Array|Buffer|undefined|null} [body]\n */\n\n/**\n * @param {CreateSignedHeadersInput} input\n * @returns {{ headers: Record<string, string>, date: string, signature: string, canonicalPayload: Buffer }}\n */\nexport function createSignedHeaders(input) {\n const date =\n typeof input.date === 'string'\n ? input.date\n : formatAppleDate(input.date ?? new Date())\n const contentType = input.contentType ?? ''\n\n const canonicalPayload = buildCanonicalRequest({\n method: input.method,\n url: input.url,\n date,\n contentType,\n body: input.body\n })\n\n const signature = signCanonicalRequest(input.apiSecret, canonicalPayload)\n const authorization = buildAuthorizationHeader({\n apiId: input.apiId,\n signature,\n date\n })\n\n const headers = {\n Accept: 'application/json',\n Authorization: authorization\n }\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n return {\n headers,\n date,\n signature,\n canonicalPayload\n }\n}\n", "import { createSignedHeaders } from './auth.js'\n\n/**\n * @typedef RequestOptions\n * @property {string} apiId\n * @property {string} apiSecret\n * @property {string} method\n * @property {string} endpoint\n * @property {string} [host]\n * @property {Record<string, string | number | boolean | undefined>} [query]\n * @property {string} [contentType]\n * @property {string|Buffer|Uint8Array|null} [body]\n * @property {string|Date} [date]\n * @property {boolean} [returnFullResponse]\n */\n\nexport class AppleNewsApiError extends Error {\n /**\n * @param {string} message\n * @param {Object} details\n * @param {number} details.status\n * @param {string} details.method\n * @param {string} details.url\n * @param {unknown[]} [details.apiErrors]\n * @param {unknown} [details.responseBody]\n */\n constructor(message, details) {\n super(message)\n this.name = 'AppleNewsApiError'\n this.status = details.status\n this.method = details.method\n this.url = details.url\n this.apiErrors = details.apiErrors\n this.responseBody = details.responseBody\n }\n}\n\n/**\n * @param {string} host\n * @param {string} endpoint\n * @param {Record<string, string | number | boolean | undefined>} [query]\n * @returns {string}\n */\nexport function buildRequestUrl(host, endpoint, query) {\n const url = new URL(`https://${host}${endpoint}`)\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) {\n continue\n }\n\n url.searchParams.set(key, String(value))\n }\n }\n\n return url.toString()\n}\n\n/**\n * @param {unknown} value\n * @returns {value is Record<string, unknown>}\n */\nfunction isObject(value) {\n return value !== null && typeof value === 'object'\n}\n\n/**\n * @param {unknown} parsed\n * @returns {unknown[]|undefined}\n */\nfunction getApiErrors(parsed) {\n if (!isObject(parsed)) {\n return undefined\n }\n\n const maybeErrors = parsed.errors\n if (!Array.isArray(maybeErrors)) {\n return undefined\n }\n\n return maybeErrors\n}\n\n/**\n * @param {unknown} parsed\n * @returns {unknown}\n */\nfunction unwrapData(parsed) {\n if (!isObject(parsed)) {\n return parsed\n }\n\n if ('data' in parsed) {\n return parsed.data\n }\n\n return parsed\n}\n\n/**\n * Execute one signed Apple News API request.\n *\n * @param {RequestOptions} options\n * @returns {Promise<unknown>}\n */\nexport async function requestSigned(options) {\n const host = options.host ?? 'news-api.apple.com'\n\n const url = buildRequestUrl(host, options.endpoint, options.query)\n const signed = createSignedHeaders({\n apiId: options.apiId,\n apiSecret: options.apiSecret,\n method: options.method,\n url,\n date: options.date,\n contentType: options.contentType,\n body: options.body\n })\n\n const response = await fetch(url, {\n method: options.method,\n headers: signed.headers,\n body: options.body ?? undefined\n })\n\n const rawBody = await response.text()\n let parsedBody = null\n\n if (rawBody.length > 0) {\n try {\n parsedBody = JSON.parse(rawBody)\n } catch {\n parsedBody = rawBody\n }\n }\n\n if (!response.ok) {\n const apiErrors = getApiErrors(parsedBody)\n throw new AppleNewsApiError(\n `${options.method.toUpperCase()} ${options.endpoint} failed with status ${response.status}`,\n {\n status: response.status,\n method: options.method.toUpperCase(),\n url,\n apiErrors,\n responseBody: parsedBody\n }\n )\n }\n\n if (parsedBody === null) {\n return null\n }\n\n if (options.returnFullResponse) {\n return parsedBody\n }\n\n return unwrapData(parsedBody)\n}\n", "const CRLF = '\\r\\n'\n\n/**\n * @typedef BundleFile\n * @property {Buffer|Uint8Array|string} data\n * @property {string} [mimeType]\n */\n\n/**\n * @param {Buffer|Uint8Array|string} data\n * @returns {Buffer}\n */\nfunction toBuffer(data) {\n if (Buffer.isBuffer(data)) {\n return data\n }\n\n if (data instanceof Uint8Array) {\n return Buffer.from(data)\n }\n\n return Buffer.from(String(data), 'utf8')\n}\n\n/**\n * @param {string} boundary\n * @param {string} name\n * @param {Buffer} value\n * @param {string} contentType\n * @param {string} [filename]\n * @returns {Buffer}\n */\nfunction buildPart(boundary, name, value, contentType, filename) {\n const lines = [`--${boundary}`]\n\n if (filename) {\n lines.push(\n `Content-Disposition: form-data; name=\"${name}\"; filename=\"${filename}\"`\n )\n } else {\n lines.push(`Content-Disposition: form-data; name=\"${name}\"`)\n }\n\n lines.push(`Content-Type: ${contentType}`)\n lines.push('')\n\n return Buffer.concat([\n Buffer.from(lines.join(CRLF) + CRLF, 'utf8'),\n value,\n Buffer.from(CRLF, 'utf8')\n ])\n}\n\n/**\n * @param {Record<string, BundleFile>|undefined} bundleFiles\n */\nfunction validateBundleFiles(bundleFiles) {\n if (!bundleFiles) {\n return\n }\n\n for (const name of Object.keys(bundleFiles)) {\n if (name === 'article.json' || name === 'metadata') {\n throw new TypeError(\n 'bundleFiles cannot contain reserved names: article.json or metadata'\n )\n }\n }\n}\n\n/**\n * @param {Object} input\n * @param {Record<string, unknown>} input.article\n * @param {Record<string, unknown>} [input.metadata]\n * @param {Record<string, BundleFile>} [input.bundleFiles]\n * @param {string} [input.boundary]\n * @returns {{ contentType: string, body: Buffer }}\n */\nexport function buildArticleMultipartBody(input) {\n if (!input.article || typeof input.article !== 'object') {\n throw new TypeError('article is required and must be an object')\n }\n\n validateBundleFiles(input.bundleFiles)\n\n const boundary = input.boundary ?? `apple-news-${Date.now().toString(16)}`\n const metadata = input.metadata ?? {}\n\n const parts = []\n parts.push(\n buildPart(\n boundary,\n 'article.json',\n Buffer.from(JSON.stringify(input.article), 'utf8'),\n 'application/json',\n 'article.json'\n )\n )\n\n parts.push(\n buildPart(\n boundary,\n 'metadata',\n Buffer.from(JSON.stringify({ data: metadata }), 'utf8'),\n 'application/json'\n )\n )\n\n if (input.bundleFiles) {\n let index = 0\n for (const [filename, file] of Object.entries(input.bundleFiles)) {\n const fieldName = `file${index}`\n index += 1\n parts.push(\n buildPart(\n boundary,\n fieldName,\n toBuffer(file.data),\n file.mimeType ?? 'application/octet-stream',\n filename\n )\n )\n }\n }\n\n parts.push(Buffer.from(`--${boundary}--${CRLF}`, 'utf8'))\n\n return {\n contentType: `multipart/form-data; boundary=${boundary}`,\n body: Buffer.concat(parts)\n }\n}\n", "import { requestSigned } from './request.js'\nimport { buildArticleMultipartBody } from './multipart.js'\n\n/**\n * @typedef AppleNewsClientConfig\n * @property {string} apiId\n * @property {string} apiSecret\n * @property {string} [host]\n */\n\nfunction assertRequired(value, name) {\n if (!value || typeof value !== 'string') {\n throw new TypeError(`${name} is required and must be a non-empty string`)\n }\n}\n\nfunction assertId(value, name) {\n if (!value || typeof value !== 'string') {\n throw new TypeError(`${name} is required and must be a non-empty string`)\n }\n}\n\n/**\n * @typedef {Object} ArticleBundleFile\n * @property {Buffer|Uint8Array|string} data\n * @property {string} [mimeType]\n */\n\n/**\n * @param {Object} options\n * @param {boolean} [options.isPreview=true]\n * @param {boolean} [options.isSponsored=false]\n * @param {boolean} [options.isPaid=false]\n * @param {string[]} [options.sections]\n * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]\n * @param {string} [options.revision]\n * @param {string} host\n * @param {boolean} includeRevision\n */\nfunction buildMetadata(options, host, includeRevision = false) {\n const metadata = includeRevision\n ? {}\n : {\n isPreview: options.isPreview ?? true,\n isSponsored: options.isSponsored ?? false,\n isPaid: options.isPaid ?? false\n }\n\n if (includeRevision) {\n if (options.isPreview !== undefined) {\n metadata.isPreview = options.isPreview\n }\n\n if (options.isSponsored !== undefined) {\n metadata.isSponsored = options.isSponsored\n }\n\n if (options.isPaid !== undefined) {\n metadata.isPaid = options.isPaid\n }\n }\n\n if (options.sections !== undefined) {\n metadata.links = {\n sections: options.sections.map(\n (sectionId) =>\n `https://${host}/sections/${encodeURIComponent(sectionId)}`\n )\n }\n }\n\n if (options.maturityRating !== undefined) {\n metadata.maturityRating = options.maturityRating\n }\n\n if (includeRevision) {\n metadata.revision = options.revision\n }\n\n return metadata\n}\n\n/**\n * @typedef {Object} SharedOptions\n * @property {string|Date} [date]\n */\n\n/**\n * @param {Record<string, unknown>|undefined} options\n * @returns {SharedOptions}\n */\nfunction getSharedOptions(options) {\n return {\n date: options?.date\n }\n}\n\nexport class AppleNewsClient {\n /**\n * @param {AppleNewsClientConfig} config\n */\n constructor(config) {\n assertRequired(config?.apiId, 'apiId')\n assertRequired(config?.apiSecret, 'apiSecret')\n\n this.apiId = config.apiId\n this.apiSecret = config.apiSecret\n this.host = config.host ?? 'news-api.apple.com'\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {string|Date} [options.date]\n */\n async readChannel(options) {\n assertId(options?.channelId, 'channelId')\n return this.#request(\n 'GET',\n `/channels/${options.channelId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {string|Date} [options.date]\n */\n async listSections(options) {\n assertId(options?.channelId, 'channelId')\n return this.#request(\n 'GET',\n `/channels/${options.channelId}/sections`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.sectionId\n * @param {string|Date} [options.date]\n */\n async readSection(options) {\n assertId(options?.sectionId, 'sectionId')\n return this.#request(\n 'GET',\n `/sections/${options.sectionId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.articleId\n * @param {string|Date} [options.date]\n */\n async readArticle(options) {\n assertId(options?.articleId, 'articleId')\n return this.#request(\n 'GET',\n `/articles/${options.articleId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.articleId\n * @param {string|Date} [options.date]\n */\n async deleteArticle(options) {\n assertId(options?.articleId, 'articleId')\n return this.#request(\n 'DELETE',\n `/articles/${options.articleId}`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Record<string, unknown>} options\n * @param {string} [options.channelId]\n * @param {string} [options.sectionId]\n * @param {number} [options.pageSize] An integer from 1 to 100\n * @param {string} [options.pageToken] Opaque token from a previous response\n * @param {string} [options.fromDate] ISO 8601 lower bound\n * @param {string} [options.toDate] ISO 8601 upper bound\n * @param {'ASC'|'DESC'} [options.sortDir]\n * @param {string|Date} [options.date] HHMAC signing timestamp, not a filter\n * @returns {Promise<Record<string, unknown>>} Full search response, including pagination metadata\n */\n async searchArticles(options) {\n if (!options?.channelId && !options?.sectionId) {\n throw new TypeError(\n 'searchArticles requires either channelId or sectionId'\n )\n }\n\n if (options.channelId && options.sectionId) {\n throw new TypeError(\n 'searchArticles accepts either channelId or sectionId, not both'\n )\n }\n\n if (\n options.pageSize !== undefined &&\n (!Number.isInteger(options.pageSize) ||\n options.pageSize < 1 ||\n options.pageSize > 100)\n ) {\n throw new TypeError('pageSize must be an integer between 1 and 100')\n }\n\n if (\n options.sortDir !== undefined &&\n options.sortDir !== 'ASC' &&\n options.sortDir !== 'DESC'\n ) {\n throw new TypeError('sortDir must be either ASC or DESC')\n }\n\n const endpoint = options.channelId\n ? `/channels/${options.channelId}/articles`\n : `/sections/${options.sectionId}/articles`\n\n const query = { ...options }\n const date = query.date\n delete query.channelId\n delete query.sectionId\n delete query.date\n\n return this.#request('GET', endpoint, {\n date,\n query,\n returnFullResponse: true\n })\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {Record<string, unknown>} options.article\n * @param {Record<string, ArticleBundleFile>} [options.bundleFiles]\n * @param {boolean} [options.isPreview=true]\n * @param {boolean} [options.isSponsored=false]\n * @param {boolean} [options.isPaid=false]\n * @param {string[]} [options.sections]\n * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]\n * @param {string|Date} [options.date]\n */\n async createArticle(options) {\n assertId(options?.channelId, 'channelId')\n\n const multipart = buildArticleMultipartBody({\n article: options.article,\n metadata: buildMetadata(options, this.host),\n bundleFiles: options.bundleFiles\n })\n\n return this.#request('POST', `/channels/${options.channelId}/articles`, {\n date: options.date,\n contentType: multipart.contentType,\n body: multipart.body\n })\n }\n\n /**\n * @param {Object} options\n * @param {string} options.articleId\n * @param {string} options.revision\n * @param {Record<string, unknown>} options.article\n * @param {Record<string, ArticleBundleFile>} [options.bundleFiles]\n * @param {boolean} [options.isPreview]\n * @param {boolean} [options.isSponsored]\n * @param {boolean} [options.isPaid]\n * @param {string[]} [options.sections]\n * @param {'KIDS'|'MATURE'|'GENERAL'} [options.maturityRating]\n * @param {string|Date} [options.date]\n */\n async updateArticle(options) {\n assertId(options?.articleId, 'articleId')\n assertId(options?.revision, 'revision')\n\n const multipart = buildArticleMultipartBody({\n article: options.article,\n metadata: buildMetadata(options, this.host, true),\n bundleFiles: options.bundleFiles\n })\n\n return this.#request('POST', `/articles/${options.articleId}`, {\n date: options.date,\n contentType: multipart.contentType,\n body: multipart.body\n })\n }\n\n /**\n * @param {Object} options\n * @param {string} options.channelId\n * @param {string|Date} [options.date]\n */\n async readChannelQuota(options) {\n assertId(options?.channelId, 'channelId')\n return this.#request(\n 'GET',\n `/channels/${options.channelId}/quota`,\n getSharedOptions(options)\n )\n }\n\n /**\n * @param {Object} options\n * @param {string} options.sectionId\n * @param {string[]} options.articleIds\n * @param {string|Date} [options.date]\n */\n async promoteArticles(options) {\n assertId(options?.sectionId, 'sectionId')\n\n if (!Array.isArray(options?.articleIds)) {\n throw new TypeError('articleIds is required and must be an array')\n }\n\n const body = JSON.stringify({\n data: { promotedArticles: options.articleIds }\n })\n\n return this.#request(\n 'POST',\n `/sections/${options.sectionId}/promotedArticles`,\n {\n date: options.date,\n contentType: 'application/json',\n body\n }\n )\n }\n\n /**\n * @param {string} method\n * @param {string} endpoint\n * @param {Object} [options={}]\n * @param {string|Date} [options.date]\n * @param {Record<string, string|number|boolean|undefined>} [options.query]\n * @param {string} [options.contentType]\n * @param {string|Buffer|Uint8Array|null} [options.body]\n * @param {boolean} [options.returnFullResponse]\n */\n async #request(method, endpoint, options = {}) {\n return requestSigned({\n apiId: this.apiId,\n apiSecret: this.apiSecret,\n host: this.host,\n method,\n endpoint,\n date: options.date,\n query: options.query,\n contentType: options.contentType,\n body: options.body,\n returnFullResponse: options.returnFullResponse\n })\n }\n}\n", "/**\n * @typedef BundleFetchResult\n * @property {Buffer} data\n * @property {string} mimeType\n */\n\n/**\n * @param {Record<string, string>} urlMap\n * @returns {Promise<Record<string, BundleFetchResult>>}\n */\nexport async function fetchBundleFiles(urlMap) {\n const result = {}\n\n for (const [filename, url] of Object.entries(urlMap)) {\n const response = await fetch(url)\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch bundle file ${filename} from ${url}: ${response.status}`\n )\n }\n\n const arrayBuffer = await response.arrayBuffer()\n const data = Buffer.from(arrayBuffer)\n const mimeType =\n response.headers.get('content-type') ?? 'application/octet-stream'\n\n result[filename] = {\n data,\n mimeType\n }\n }\n\n return result\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["toBuffer"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stephensauceda/apple-news",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "Modern Apple News API client for Node.js",
5
5
  "author": "Stephen Sauceda",
6
6
  "type": "module",