@financial-times/content-curation-client 5.4.0 → 6.1.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 +2 -51
- package/dist/_tsup-dts-rollup.d.cts +268 -3211
- package/dist/_tsup-dts-rollup.d.ts +268 -3211
- package/dist/index.cjs +84 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -6
- package/dist/index.d.ts +0 -6
- package/dist/index.js +144 -190
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -523,6 +523,87 @@ function trimTrailingSlashes(value) {
|
|
|
523
523
|
return end === value.length ? value : value.slice(0, end);
|
|
524
524
|
}
|
|
525
525
|
|
|
526
|
+
// src/schemas/ftpink/legacyHubPage/index.ts
|
|
527
|
+
|
|
528
|
+
var LegacyFlourishChildSchema = _zod.z.object({
|
|
529
|
+
source: _zod.z.literal("flourish"),
|
|
530
|
+
properties: _zod.z.object({
|
|
531
|
+
id: _zod.z.string().min(1)
|
|
532
|
+
// e.g. "visualisation/21901162"
|
|
533
|
+
})
|
|
534
|
+
});
|
|
535
|
+
var LegacyListChildSchema = _zod.z.object({
|
|
536
|
+
source: _zod.z.literal("list"),
|
|
537
|
+
properties: _zod.z.object({
|
|
538
|
+
id: _zod.z.string().uuid(),
|
|
539
|
+
maxItems: _zod.z.number().optional()
|
|
540
|
+
})
|
|
541
|
+
});
|
|
542
|
+
var LegacyContentChildSchema = _zod.z.object({
|
|
543
|
+
source: _zod.z.literal("content"),
|
|
544
|
+
properties: _zod.z.object({
|
|
545
|
+
ids: _zod.z.array(_zod.z.string()).nonempty()
|
|
546
|
+
})
|
|
547
|
+
});
|
|
548
|
+
var LegacyContainerChildSchema = _zod.z.discriminatedUnion("source", [
|
|
549
|
+
LegacyFlourishChildSchema,
|
|
550
|
+
LegacyListChildSchema,
|
|
551
|
+
LegacyContentChildSchema
|
|
552
|
+
]);
|
|
553
|
+
var LegacyTopperSchema = _zod.z.object({
|
|
554
|
+
type: _zod.z.literal("topper-basic"),
|
|
555
|
+
properties: _zod.z.object({
|
|
556
|
+
title: _zod.z.string(),
|
|
557
|
+
sponsorText: _zod.z.string().optional(),
|
|
558
|
+
sponsorImage: _zod.z.string().url().optional()
|
|
559
|
+
})
|
|
560
|
+
});
|
|
561
|
+
var LegacyInfoBoxSchema = _zod.z.object({
|
|
562
|
+
type: _zod.z.literal("info-box"),
|
|
563
|
+
properties: _zod.z.object({
|
|
564
|
+
bodyHTML: _zod.z.string(),
|
|
565
|
+
title: _zod.z.string().optional()
|
|
566
|
+
})
|
|
567
|
+
});
|
|
568
|
+
var LegacyContainerSchema = _zod.z.object({
|
|
569
|
+
type: _zod.z.literal("container"),
|
|
570
|
+
children: _zod.z.array(LegacyContainerChildSchema).min(1),
|
|
571
|
+
properties: _zod.z.object({
|
|
572
|
+
title: _zod.z.string().optional(),
|
|
573
|
+
design: _zod.z.enum(["chart", "four-story", "freeform", "hero-lead"]).default("freeform"),
|
|
574
|
+
backgroundColor: _zod.z.string().optional()
|
|
575
|
+
})
|
|
576
|
+
});
|
|
577
|
+
var LegacyExperimentSchema = _zod.z.object({
|
|
578
|
+
type: _zod.z.literal("experiment"),
|
|
579
|
+
children: _zod.z.tuple([]),
|
|
580
|
+
properties: _zod.z.object({
|
|
581
|
+
experimentName: _zod.z.string(),
|
|
582
|
+
id: _zod.z.string(),
|
|
583
|
+
title: _zod.z.string().optional(),
|
|
584
|
+
config: _zod.z.object({
|
|
585
|
+
value: _zod.z.unknown().optional(),
|
|
586
|
+
// Hub pages support experiments with HTML and Text.
|
|
587
|
+
// For now we just support JSON. As we migrate pages, this may change.
|
|
588
|
+
format: _zod.z.enum(["json"]).default("json")
|
|
589
|
+
}).partial().optional()
|
|
590
|
+
})
|
|
591
|
+
});
|
|
592
|
+
var LegacyBlockSchema = _zod.z.discriminatedUnion("type", [
|
|
593
|
+
LegacyTopperSchema,
|
|
594
|
+
LegacyInfoBoxSchema,
|
|
595
|
+
LegacyContainerSchema,
|
|
596
|
+
LegacyExperimentSchema
|
|
597
|
+
]);
|
|
598
|
+
var LegacyPageStructureOutputSchema = _zod.z.object({
|
|
599
|
+
uuid: _zod.z.string().uuid(),
|
|
600
|
+
title: _zod.z.string(),
|
|
601
|
+
conceptId: _zod.z.string().uuid().optional(),
|
|
602
|
+
themeName: _zod.z.string().optional(),
|
|
603
|
+
metaDescription: _zod.z.string().optional(),
|
|
604
|
+
blocks: _zod.z.array(LegacyBlockSchema)
|
|
605
|
+
});
|
|
606
|
+
|
|
526
607
|
// src/schemas/ftpink/page/index.ts
|
|
527
608
|
|
|
528
609
|
|
|
@@ -593,10 +674,6 @@ function defineSliceSchema(options) {
|
|
|
593
674
|
});
|
|
594
675
|
return { InputSchema, OutputSchema };
|
|
595
676
|
}
|
|
596
|
-
var HomepageSlice = defineSliceSchema({
|
|
597
|
-
typeName: "HomepageSlice",
|
|
598
|
-
propsShape: BasePageItemProps.optional()
|
|
599
|
-
});
|
|
600
677
|
var InteractiveSlice = defineSliceSchema({
|
|
601
678
|
typeName: "Interactive",
|
|
602
679
|
propsShape: BasePageItemProps.extend({
|
|
@@ -651,7 +728,6 @@ var StoryGroupSlice = defineSliceSchema({
|
|
|
651
728
|
})
|
|
652
729
|
});
|
|
653
730
|
var SliceApiInputSchema = _zod.z.discriminatedUnion("type", [
|
|
654
|
-
HomepageSlice.InputSchema,
|
|
655
731
|
InteractiveSlice.InputSchema,
|
|
656
732
|
ExperimentSlice.InputSchema,
|
|
657
733
|
StripSlice.InputSchema,
|
|
@@ -660,7 +736,6 @@ var SliceApiInputSchema = _zod.z.discriminatedUnion("type", [
|
|
|
660
736
|
StoryGroupSlice.InputSchema
|
|
661
737
|
]);
|
|
662
738
|
var SliceApiOutputSchema = _zod.z.discriminatedUnion("type", [
|
|
663
|
-
HomepageSlice.OutputSchema,
|
|
664
739
|
InteractiveSlice.OutputSchema,
|
|
665
740
|
ExperimentSlice.OutputSchema,
|
|
666
741
|
StripSlice.OutputSchema,
|
|
@@ -676,132 +751,19 @@ var BasePagePropertiesSchema = _zod.z.object({
|
|
|
676
751
|
metaDescription: _zod.z.string().optional(),
|
|
677
752
|
pageTheme: _zod.z.string().optional(),
|
|
678
753
|
sponsorText: _zod.z.string().optional(),
|
|
679
|
-
sponsorImage: _zod.z.string().url().optional()
|
|
754
|
+
sponsorImage: _zod.z.string().url().optional(),
|
|
755
|
+
pageCategory: _zod.z.string().optional()
|
|
680
756
|
});
|
|
681
757
|
var PageStructureInputSchema = _zod.z.object({
|
|
682
758
|
properties: BasePagePropertiesSchema,
|
|
683
759
|
children: _zod.z.array(SliceApiInputSchema)
|
|
684
760
|
});
|
|
685
|
-
var HomepageStructureInputSchema = PageStructureInputSchema.extend({
|
|
686
|
-
properties: BasePagePropertiesSchema.extend({
|
|
687
|
-
// This is optional for the input. If clients don't send it, we generate a uuid.
|
|
688
|
-
homepageListId: _zod.z.string().uuid()
|
|
689
|
-
})
|
|
690
|
-
});
|
|
691
761
|
var PageStructureOutputSchema = _zod.z.object({
|
|
692
762
|
type: _zod.z.literal("Page"),
|
|
693
763
|
schemaVersion: _zod.z.number(),
|
|
694
764
|
properties: BasePagePropertiesSchema,
|
|
695
765
|
children: _zod.z.array(SliceApiOutputSchema)
|
|
696
766
|
});
|
|
697
|
-
var HomepageStructureOutputSchema = PageStructureOutputSchema.extend({
|
|
698
|
-
type: _zod.z.literal("Homepage"),
|
|
699
|
-
properties: BasePagePropertiesSchema.extend({
|
|
700
|
-
homepageListId: _zod.z.string().uuid()
|
|
701
|
-
})
|
|
702
|
-
});
|
|
703
|
-
|
|
704
|
-
// src/homepage.ts
|
|
705
|
-
var HomepageClient = class extends BaseApiClient {
|
|
706
|
-
async getStructure(pageId) {
|
|
707
|
-
return this.get(`/v1/homepage/${pageId}/structure`, HomepageStructureOutputSchema);
|
|
708
|
-
}
|
|
709
|
-
async getStructuresByHomepageListId(homepageListId) {
|
|
710
|
-
return this.get(
|
|
711
|
-
`/v1/homepage/list/${homepageListId}/structures`,
|
|
712
|
-
HomepageStructureOutputSchema.array()
|
|
713
|
-
);
|
|
714
|
-
}
|
|
715
|
-
async upsertStructure(pageId, data) {
|
|
716
|
-
return this.put(
|
|
717
|
-
`/v1/homepage/${pageId}/structure`,
|
|
718
|
-
data,
|
|
719
|
-
HomepageStructureInputSchema,
|
|
720
|
-
HomepageStructureOutputSchema
|
|
721
|
-
);
|
|
722
|
-
}
|
|
723
|
-
};
|
|
724
|
-
|
|
725
|
-
// src/schemas/ftpink/legacyHubPage/index.ts
|
|
726
|
-
|
|
727
|
-
var LegacyFlourishChildSchema = _zod.z.object({
|
|
728
|
-
source: _zod.z.literal("flourish"),
|
|
729
|
-
properties: _zod.z.object({
|
|
730
|
-
id: _zod.z.string().min(1)
|
|
731
|
-
// e.g. "visualisation/21901162"
|
|
732
|
-
})
|
|
733
|
-
});
|
|
734
|
-
var LegacyListChildSchema = _zod.z.object({
|
|
735
|
-
source: _zod.z.literal("list"),
|
|
736
|
-
properties: _zod.z.object({
|
|
737
|
-
id: _zod.z.string().uuid(),
|
|
738
|
-
maxItems: _zod.z.number().optional()
|
|
739
|
-
})
|
|
740
|
-
});
|
|
741
|
-
var LegacyContentChildSchema = _zod.z.object({
|
|
742
|
-
source: _zod.z.literal("content"),
|
|
743
|
-
properties: _zod.z.object({
|
|
744
|
-
ids: _zod.z.array(_zod.z.string()).nonempty()
|
|
745
|
-
})
|
|
746
|
-
});
|
|
747
|
-
var LegacyContainerChildSchema = _zod.z.discriminatedUnion("source", [
|
|
748
|
-
LegacyFlourishChildSchema,
|
|
749
|
-
LegacyListChildSchema,
|
|
750
|
-
LegacyContentChildSchema
|
|
751
|
-
]);
|
|
752
|
-
var LegacyTopperSchema = _zod.z.object({
|
|
753
|
-
type: _zod.z.literal("topper-basic"),
|
|
754
|
-
properties: _zod.z.object({
|
|
755
|
-
title: _zod.z.string(),
|
|
756
|
-
sponsorText: _zod.z.string().optional(),
|
|
757
|
-
sponsorImage: _zod.z.string().url().optional()
|
|
758
|
-
})
|
|
759
|
-
});
|
|
760
|
-
var LegacyInfoBoxSchema = _zod.z.object({
|
|
761
|
-
type: _zod.z.literal("info-box"),
|
|
762
|
-
properties: _zod.z.object({
|
|
763
|
-
bodyHTML: _zod.z.string(),
|
|
764
|
-
title: _zod.z.string().optional()
|
|
765
|
-
})
|
|
766
|
-
});
|
|
767
|
-
var LegacyContainerSchema = _zod.z.object({
|
|
768
|
-
type: _zod.z.literal("container"),
|
|
769
|
-
children: _zod.z.array(LegacyContainerChildSchema).min(1),
|
|
770
|
-
properties: _zod.z.object({
|
|
771
|
-
title: _zod.z.string().optional(),
|
|
772
|
-
design: _zod.z.enum(["chart", "four-story", "freeform", "hero-lead"]).default("freeform"),
|
|
773
|
-
backgroundColor: _zod.z.string().optional()
|
|
774
|
-
})
|
|
775
|
-
});
|
|
776
|
-
var LegacyExperimentSchema = _zod.z.object({
|
|
777
|
-
type: _zod.z.literal("experiment"),
|
|
778
|
-
children: _zod.z.tuple([]),
|
|
779
|
-
properties: _zod.z.object({
|
|
780
|
-
experimentName: _zod.z.string(),
|
|
781
|
-
id: _zod.z.string(),
|
|
782
|
-
title: _zod.z.string().optional(),
|
|
783
|
-
config: _zod.z.object({
|
|
784
|
-
value: _zod.z.unknown().optional(),
|
|
785
|
-
// Hub pages support experiments with HTML and Text.
|
|
786
|
-
// For now we just support JSON. As we migrate pages, this may change.
|
|
787
|
-
format: _zod.z.enum(["json"]).default("json")
|
|
788
|
-
}).partial().optional()
|
|
789
|
-
})
|
|
790
|
-
});
|
|
791
|
-
var LegacyBlockSchema = _zod.z.discriminatedUnion("type", [
|
|
792
|
-
LegacyTopperSchema,
|
|
793
|
-
LegacyInfoBoxSchema,
|
|
794
|
-
LegacyContainerSchema,
|
|
795
|
-
LegacyExperimentSchema
|
|
796
|
-
]);
|
|
797
|
-
var LegacyPageStructureOutputSchema = _zod.z.object({
|
|
798
|
-
uuid: _zod.z.string().uuid(),
|
|
799
|
-
title: _zod.z.string(),
|
|
800
|
-
conceptId: _zod.z.string().uuid().optional(),
|
|
801
|
-
themeName: _zod.z.string().optional(),
|
|
802
|
-
metaDescription: _zod.z.string().optional(),
|
|
803
|
-
blocks: _zod.z.array(LegacyBlockSchema)
|
|
804
|
-
});
|
|
805
767
|
|
|
806
768
|
// src/schemas/ftpink/draft/index.ts
|
|
807
769
|
|
|
@@ -861,14 +823,9 @@ var PageClient = class extends BaseApiClient {
|
|
|
861
823
|
|
|
862
824
|
// src/client.ts
|
|
863
825
|
var ApiClient = class extends BaseApiClient {
|
|
864
|
-
/**
|
|
865
|
-
* Homepage API endpoints
|
|
866
|
-
*/
|
|
867
|
-
|
|
868
826
|
|
|
869
827
|
constructor(config) {
|
|
870
828
|
super(config);
|
|
871
|
-
this.homepage = new HomepageClient(config);
|
|
872
829
|
this.page = new PageClient(config);
|
|
873
830
|
}
|
|
874
831
|
};
|
|
@@ -895,8 +852,5 @@ var ApiClient = class extends BaseApiClient {
|
|
|
895
852
|
|
|
896
853
|
|
|
897
854
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
exports.ApiClient = ApiClient; exports.ApiClientError = ApiClientError; exports.ApiErrorCode = ApiErrorCode; exports.ApiErrorPayloadSchema = ApiErrorPayloadSchema; exports.ApiErrorResponseSchema = ApiErrorResponseSchema; exports.ApiGatewayError = ApiGatewayError; exports.ApiResponseSchema = ApiResponseSchema; exports.ApiServiceError = ApiServiceError; exports.ApiSuccessResponseSchema = ApiSuccessResponseSchema; exports.ApiTransportError = ApiTransportError; exports.DraftContributorInputSchema = DraftContributorInputSchema; exports.DraftContributorSchema = DraftContributorSchema; exports.DraftSchema = DraftSchema; exports.HomepageClient = HomepageClient; exports.HomepageStructureInputSchema = HomepageStructureInputSchema; exports.HomepageStructureOutputSchema = HomepageStructureOutputSchema; exports.LegacyPageStructureOutputSchema = LegacyPageStructureOutputSchema; exports.PageClient = PageClient; exports.PageDraftSchema = PageDraftSchema; exports.PageStructureInputSchema = PageStructureInputSchema; exports.PageStructureOutputSchema = PageStructureOutputSchema; exports.PersistPageDraftInputSchema = PersistPageDraftInputSchema; exports.ProseMirrorDocSchema = ProseMirrorDocSchema; exports.SliceApiInputSchema = SliceApiInputSchema; exports.SliceApiOutputSchema = SliceApiOutputSchema;
|
|
855
|
+
exports.ApiClient = ApiClient; exports.ApiClientError = ApiClientError; exports.ApiErrorCode = ApiErrorCode; exports.ApiErrorPayloadSchema = ApiErrorPayloadSchema; exports.ApiErrorResponseSchema = ApiErrorResponseSchema; exports.ApiGatewayError = ApiGatewayError; exports.ApiResponseSchema = ApiResponseSchema; exports.ApiServiceError = ApiServiceError; exports.ApiSuccessResponseSchema = ApiSuccessResponseSchema; exports.ApiTransportError = ApiTransportError; exports.DraftContributorInputSchema = DraftContributorInputSchema; exports.DraftContributorSchema = DraftContributorSchema; exports.DraftSchema = DraftSchema; exports.LegacyPageStructureOutputSchema = LegacyPageStructureOutputSchema; exports.PageClient = PageClient; exports.PageDraftSchema = PageDraftSchema; exports.PageStructureInputSchema = PageStructureInputSchema; exports.PageStructureOutputSchema = PageStructureOutputSchema; exports.PersistPageDraftInputSchema = PersistPageDraftInputSchema; exports.ProseMirrorDocSchema = ProseMirrorDocSchema; exports.SliceApiInputSchema = SliceApiInputSchema; exports.SliceApiOutputSchema = SliceApiOutputSchema;
|
|
902
856
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/circleci/repo/packages/content-curation-client/dist/index.cjs","../src/errors.ts","../src/internal/error-factories.ts","../src/schemas/response.ts","../src/internal/response-handling.ts","../src/internal/request-lifecycle.ts","../src/base.ts","../src/schemas/ftpink/page/index.ts","../src/schemas/prosemirror.ts","../src/homepage.ts","../src/schemas/ftpink/legacyHubPage/index.ts","../src/schemas/ftpink/draft/index.ts","../src/page.ts","../src/client.ts"],"names":["z"],"mappings":"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","file":"/home/circleci/repo/packages/content-curation-client/dist/index.cjs","sourcesContent":[null,"import type { ApiErrorPayload } from \"./schemas/response\";\n\n/** Where the failing request broke down. */\nexport type ApiClientErrorOrigin = \"transport\" | \"gateway\" | \"service\";\n\n/** The transport failure mode when no HTTP response was received. */\nexport type ApiTransportKind = \"abort\" | \"timeout\" | \"network\";\n\n/** Machine-readable codes exposed by the client error model. */\nexport type ApiClientErrorCode =\n\t| ApiErrorPayload[\"code\"]\n\t| \"API_GATEWAY_ERROR\"\n\t| \"API_TRANSPORT_ERROR\";\n\n/**\n * Shared error payload shape used by all client-generated errors.\n *\n * Service-origin errors use the validated `ApiErrorPayload` returned by the API.\n * Gateway and transport errors synthesize the same top-level fields so callers\n * can handle them consistently.\n */\nexport type ApiClientErrorPayload = {\n\tcode: ApiClientErrorCode;\n\tmessage: string;\n\tdetails?: string;\n\tpath?: string;\n\ttimestamp?: string;\n};\n\ntype ApiClientErrorMetadata = {\n\torigin: ApiClientErrorOrigin;\n\turl?: string;\n\tcontentType?: string;\n\tbodyText?: string;\n\tcause?: unknown;\n};\n\ntype ApiTransportErrorMetadata = Omit<ApiClientErrorMetadata, \"origin\"> & {\n\ttransportKind: ApiTransportKind;\n};\n\n/**\n * Base error type for all failures surfaced by the client package.\n */\nexport class ApiClientError extends Error {\n\t/** The machine-readable error payload exposed by the client. */\n\tpublic payload: ApiClientErrorPayload;\n\t/** The machine-readable error code. */\n\tpublic code: ApiClientErrorPayload[\"code\"];\n\t/** Additional diagnostic detail captured by the client. */\n\tpublic details?: string;\n\t/** The API path associated with the failing request. */\n\tpublic path?: string;\n\t/** Optional timestamp supplied by the upstream service. */\n\tpublic timestamp?: string;\n\t/** Indicates whether the failure originated from transport, gateway, or service handling. */\n\tpublic origin: ApiClientErrorOrigin;\n\t/** The fully qualified request URL, when available. */\n\tpublic url?: string;\n\t/** The response content type, when a response was received. */\n\tpublic contentType?: string;\n\t/** A truncated copy of the raw response body, when captured. */\n\tpublic bodyText?: string;\n\t/** The upstream request identifier, when available. */\n\tpublic requestId?: string;\n\t/** The HTTP status code reported by the service or gateway. */\n\tpublic statusCode: number;\n\t/** The underlying thrown error, if there was one. */\n\tpublic override cause?: unknown;\n\n\tconstructor(\n\t\tpayload: ApiClientErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId?: string,\n\t\tmetadata: ApiClientErrorMetadata = { origin: \"service\" },\n\t) {\n\t\tsuper(payload.message);\n\t\tthis.name = new.target.name;\n\t\tthis.payload = payload;\n\t\tthis.statusCode = statusCode;\n\t\tthis.requestId = requestId;\n\t\tthis.code = payload.code;\n\t\tthis.details = payload.details;\n\t\tthis.path = payload.path;\n\t\tthis.timestamp = payload.timestamp;\n\t\tthis.origin = metadata.origin;\n\t\tthis.url = metadata.url;\n\t\tthis.contentType = metadata.contentType;\n\t\tthis.bodyText = metadata.bodyText;\n\t\tthis.cause = metadata.cause;\n\t}\n}\n\n/**\n * Error raised when the request fails before any HTTP response is available.\n */\nexport class ApiTransportError extends ApiClientError {\n\tpublic override payload: ApiClientErrorPayload;\n\tpublic override origin: \"transport\";\n\t/** Whether the failure was caused by an abort, timeout, or generic network problem. */\n\tpublic transportKind: ApiTransportKind;\n\n\tconstructor(\n\t\tpayload: ApiClientErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId: string | undefined,\n\t\tmetadata: ApiTransportErrorMetadata,\n\t) {\n\t\tsuper(payload, statusCode, requestId, {\n\t\t\t...metadata,\n\t\t\torigin: \"transport\",\n\t\t});\n\t\tthis.payload = payload;\n\t\tthis.origin = \"transport\";\n\t\tthis.transportKind = metadata.transportKind;\n\t}\n}\n\n/**\n * Error raised when the request reached API Gateway but did not produce a\n * valid service-level error envelope.\n */\nexport class ApiGatewayError extends ApiClientError {\n\tpublic override payload: ApiClientErrorPayload;\n\tpublic override origin: \"gateway\";\n\n\tconstructor(\n\t\tpayload: ApiClientErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId?: string,\n\t\tmetadata: Omit<ApiClientErrorMetadata, \"origin\"> = {},\n\t) {\n\t\tsuper(payload, statusCode, requestId, {\n\t\t\t...metadata,\n\t\t\torigin: \"gateway\",\n\t\t});\n\t\tthis.payload = payload;\n\t\tthis.origin = \"gateway\";\n\t}\n}\n\n/**\n * Error raised when the root service returns a valid JSON API error envelope,\n * or when a successful response cannot be interpreted as the expected API\n * success envelope.\n */\nexport class ApiServiceError extends ApiClientError {\n\tpublic override payload: ApiErrorPayload;\n\tpublic override origin: \"service\";\n\n\tconstructor(\n\t\tpayload: ApiErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId?: string,\n\t\tmetadata: Omit<ApiClientErrorMetadata, \"origin\"> = {},\n\t) {\n\t\tsuper(payload, statusCode, requestId, {\n\t\t\t...metadata,\n\t\t\torigin: \"service\",\n\t\t});\n\t\tthis.payload = payload;\n\t\tthis.origin = \"service\";\n\t}\n}\n","import {\n\tApiGatewayError,\n\tApiServiceError,\n\tApiTransportError,\n\ttype ApiTransportKind,\n} from \"../errors\";\n\ntype GatewayErrorOptions = {\n\tcontentType?: string;\n\tbodyText?: string;\n\tdetails: string;\n\trequestId?: string;\n\tcause?: unknown;\n};\n\ntype UnexpectedServiceResponseOptions = GatewayErrorOptions;\n\n/**\n * Wraps a fetch failure that happened before any response was available.\n */\nexport function createTransportError(path: string, url: string, error: unknown): ApiTransportError {\n\tconst transportKind = classifyTransportFailure(error);\n\tconst message = describeTransportFailure(transportKind);\n\tconst causeDetails = getErrorDiagnosticMessage(error);\n\tconst details = causeDetails ? `${message} Cause: ${causeDetails}` : message;\n\n\treturn new ApiTransportError(\n\t\t{\n\t\t\tcode: \"API_TRANSPORT_ERROR\",\n\t\t\tmessage,\n\t\t\tdetails,\n\t\t\tpath,\n\t\t},\n\t\t0,\n\t\tundefined,\n\t\t{\n\t\t\ttransportKind,\n\t\t\turl,\n\t\t\tcause: error,\n\t\t},\n\t);\n}\n\n/**\n * Builds a gateway-origin client error after the caller has already decided the response does not\n * represent a validated service error envelope.\n */\nexport function createGatewayError(\n\tpath: string,\n\turl: string,\n\tstatusCode: number,\n\toptions: GatewayErrorOptions,\n): ApiGatewayError {\n\treturn new ApiGatewayError(\n\t\t{\n\t\t\tcode: \"API_GATEWAY_ERROR\",\n\t\t\tmessage: `The API gateway responded with status ${statusCode}.`,\n\t\t\tdetails: options.details,\n\t\t\tpath,\n\t\t},\n\t\tstatusCode,\n\t\toptions.requestId,\n\t\t{\n\t\t\turl,\n\t\t\tcontentType: options.contentType,\n\t\t\tbodyText: options.bodyText,\n\t\t\tcause: options.cause,\n\t\t},\n\t);\n}\n\n/**\n * Builds the fallback service error used when a 2xx response cannot be interpreted as the\n * expected Content Curation API success envelope.\n */\nexport function createUnexpectedServiceResponseError(\n\tpath: string,\n\turl: string,\n\toptions: UnexpectedServiceResponseOptions,\n): ApiServiceError {\n\treturn new ApiServiceError(\n\t\t{\n\t\t\tcode: \"INTERNAL_SERVER_ERROR\",\n\t\t\tmessage: \"Unexpected API response format\",\n\t\t\tdetails: options.details,\n\t\t\tpath,\n\t\t},\n\t\t500,\n\t\toptions.requestId,\n\t\t{\n\t\t\turl,\n\t\t\tcontentType: options.contentType,\n\t\t\tbodyText: options.bodyText,\n\t\t\tcause: options.cause,\n\t\t},\n\t);\n}\n\nfunction classifyTransportFailure(error: unknown): ApiTransportKind {\n\tconst errorName = readStringProperty(error, \"name\");\n\n\tif (errorName === \"AbortError\") {\n\t\treturn \"abort\";\n\t}\n\n\tif (errorName === \"TimeoutError\") {\n\t\treturn \"timeout\";\n\t}\n\n\tif (errorName === \"FetchError\" && readStringProperty(error, \"type\") === \"request-timeout\") {\n\t\treturn \"timeout\";\n\t}\n\n\treturn \"network\";\n}\n\nfunction describeTransportFailure(transportKind: ApiTransportKind): string {\n\tif (transportKind === \"abort\") {\n\t\treturn \"The request was aborted before a response was received.\";\n\t}\n\n\tif (transportKind === \"timeout\") {\n\t\treturn \"The request timed out before a response was received.\";\n\t}\n\n\treturn \"The request failed before a response was received.\";\n}\n\nfunction getErrorDiagnosticMessage(error: unknown): string | undefined {\n\tconst diagnosticParts = [\n\t\treadCauseCode(error),\n\t\treadStringProperty(error, \"name\"),\n\t\treadStringProperty(error, \"message\"),\n\t].filter(\n\t\t(value, index, values): value is string => Boolean(value) && values.indexOf(value) === index,\n\t);\n\n\treturn diagnosticParts.length > 0 ? diagnosticParts.join(\": \") : undefined;\n}\n\nfunction readCauseCode(error: unknown): string | undefined {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn undefined;\n\t}\n\n\tconst directCode = readStringProperty(error, \"code\");\n\tif (directCode) {\n\t\treturn directCode;\n\t}\n\n\tconst cause = (error as { cause?: unknown }).cause;\n\treturn readStringProperty(cause, \"code\");\n}\n\nfunction readStringProperty(error: unknown, property: string): string | undefined {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn undefined;\n\t}\n\n\tconst value = (error as Record<string, unknown>)[property];\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n","import { z, type ZodTypeAny } from \"zod\";\n\n/**\n * Strongly‐typed enum for all possible API error codes.\n */\nexport const ApiErrorCode = z.enum([\n\t\"UNAUTHORIZED\",\n\t\"NOT_FOUND\",\n\t\"INTERNAL_SERVER_ERROR\",\n\t\"INVALID_INPUT_DATA\",\n]);\n\n/**\n * Fields shared by both success and error envelopes (but not the discriminant).\n */\nconst BaseEnvelopeFields = z.object({\n\tstatusCode: z.number(),\n\trequestId: z.string(),\n});\n\n/**\n * Specific details carried in an error payload.\n */\nexport const ApiErrorPayloadSchema = z\n\t.object({\n\t\tcode: ApiErrorCode,\n\t\tmessage: z.string(),\n\t\tdetails: z.string().optional(),\n\t\tpath: z.string().optional(),\n\t\ttimestamp: z.string().optional(),\n\t})\n\t.strict();\n\nexport type ApiErrorPayload = z.infer<typeof ApiErrorPayloadSchema>;\n\n/**\n * Full “envelope” when the API has failed.\n */\nexport const ApiErrorResponseSchema = BaseEnvelopeFields.extend({\n\tstatus: z.literal(\"error\"),\n\terror: ApiErrorPayloadSchema,\n}).strict();\n\nexport type ApiErrorResponse = z.infer<typeof ApiErrorResponseSchema>;\n\n/**\n * Schema for a successful API response, given some data schema T.\n */\nexport function ApiSuccessResponseSchema<T extends ZodTypeAny>(dataSchema: T) {\n\treturn BaseEnvelopeFields.extend({\n\t\tstatus: z.literal(\"success\"),\n\t\tdata: dataSchema,\n\t}).strict();\n}\n\n/**\n * Union of success or error envelopes, discriminated on `status`.\n */\nexport function ApiResponseSchema<T extends ZodTypeAny>(dataSchema: T) {\n\tconst successSchema = ApiSuccessResponseSchema(dataSchema);\n\tconst errorSchema = ApiErrorResponseSchema;\n\treturn z.discriminatedUnion(\"status\", [successSchema, errorSchema]);\n}\n","import type { ZodTypeAny } from \"zod\";\nimport { ApiErrorResponseSchema, ApiResponseSchema } from \"../schemas/response\";\n\nconst GATEWAY_STATUS_CODES = new Set([499, 502, 503]);\nconst MAX_DIAGNOSTIC_BODY_LENGTH = 2000;\n\n/**\n * Captured information from a response body after the client has consumed it exactly once.\n */\nexport type ResponseBodyDiagnostics = {\n\tcontentType?: string;\n\tbodyText?: string;\n\tjson?: unknown;\n\tjsonParseError?: Error;\n};\n\n/**\n * Returns `true` when a status code should always be treated as an API Gateway failure.\n */\nexport function isGatewayStatusCode(statusCode: number): boolean {\n\treturn GATEWAY_STATUS_CODES.has(statusCode);\n}\n\n/**\n * Extracts the response content type, if one was provided.\n */\nexport function getResponseContentType(response: Response): string | undefined {\n\treturn response.headers?.get(\"content-type\") ?? undefined;\n}\n\n/**\n * Extracts the upstream request identifier, if one was provided.\n */\nexport function getResponseRequestId(response: Response): string | undefined {\n\treturn response.headers?.get(\"x-request-id\") ?? response.headers?.get(\"request-id\") ?? undefined;\n}\n\n/**\n * Reads a response body exactly once, truncates diagnostic text, and only parses JSON when the\n * declared content type says that is appropriate.\n */\nexport async function readResponseBody(response: Response): Promise<ResponseBodyDiagnostics> {\n\tconst contentType = getResponseContentType(response);\n\tlet rawBody = \"\";\n\n\ttry {\n\t\trawBody = await response.text();\n\t} catch (error) {\n\t\tawait discardResponseBody(response);\n\t\tthrow error;\n\t}\n\n\tconst bodyText = truncateBody(rawBody);\n\n\tif (!isJsonContentType(contentType) || rawBody.length === 0) {\n\t\treturn {\n\t\t\tcontentType,\n\t\t\tbodyText,\n\t\t};\n\t}\n\n\ttry {\n\t\treturn {\n\t\t\tcontentType,\n\t\t\tbodyText,\n\t\t\tjson: JSON.parse(rawBody),\n\t\t};\n\t} catch (error) {\n\t\treturn {\n\t\t\tcontentType,\n\t\t\tbodyText,\n\t\t\tjsonParseError: toError(error),\n\t\t};\n\t}\n}\n\n/**\n * Attempts to validate a consumed response body as a success-or-error API envelope.\n */\nexport function parseApiResponse<ResponseDataSchema extends ZodTypeAny>(\n\tresponseDataSchema: ResponseDataSchema,\n\tresponseBody: ResponseBodyDiagnostics,\n) {\n\tif (responseBody.json === undefined) {\n\t\treturn null;\n\t}\n\n\tconst parsedResponse = ApiResponseSchema(responseDataSchema).safeParse(responseBody.json);\n\treturn parsedResponse.success ? parsedResponse.data : null;\n}\n\n/**\n * Attempts to validate a consumed response body as a service-level error envelope.\n */\nexport function parseApiErrorResponse(responseBody: ResponseBodyDiagnostics) {\n\tif (responseBody.json === undefined) {\n\t\treturn null;\n\t}\n\n\tconst parsedError = ApiErrorResponseSchema.safeParse(responseBody.json);\n\treturn parsedError.success ? parsedError.data : null;\n}\n\n/**\n * Builds the diagnostic detail string used when a 2xx response cannot be understood as the\n * expected Content Curation API success envelope.\n */\nexport function describeUnexpectedSuccessResponse(responseBody: ResponseBodyDiagnostics): string {\n\tif (responseBody.jsonParseError) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t\"The service reported a JSON response but the body could not be parsed as JSON.\",\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\tif (!responseBody.contentType || !isJsonContentType(responseBody.contentType)) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t\"The service returned a success status without a JSON response body.\",\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\treturn buildDiagnosticDetails(\n\t\t\"The service returned JSON, but it did not match the expected Content Curation API envelope.\",\n\t\tresponseBody,\n\t);\n}\n\n/**\n * Builds the diagnostic detail string used when a non-success response should be treated as a\n * gateway-origin failure rather than a validated service error.\n */\nexport function describeGatewayResponse(\n\tstatusCode: number,\n\tresponseBody: ResponseBodyDiagnostics,\n): string {\n\tif (responseBody.jsonParseError) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t`The non-success response with status ${statusCode} declared a JSON content type, but its body could not be parsed as JSON.`,\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\tif (!responseBody.contentType || !isJsonContentType(responseBody.contentType)) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t`The non-success response with status ${statusCode} was not a valid service JSON error envelope.`,\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\treturn buildDiagnosticDetails(\n\t\t`The non-success response with status ${statusCode} returned JSON, but it did not match the service error envelope.`,\n\t\tresponseBody,\n\t);\n}\n\n/**\n * Best-effort response cleanup for the rare case where reading the body throws before completion.\n */\nasync function discardResponseBody(response: Response): Promise<void> {\n\tconst body = response.body as unknown;\n\tif (!body) {\n\t\treturn;\n\t}\n\n\tif (typeof (body as { cancel?: () => Promise<void> }).cancel === \"function\") {\n\t\ttry {\n\t\t\tawait (body as { cancel: () => Promise<void> }).cancel();\n\t\t\treturn;\n\t\t} catch {\n\t\t\t// Best effort only.\n\t\t}\n\t}\n\n\tif (\n\t\ttypeof (body as { resume?: () => void }).resume === \"function\" &&\n\t\ttypeof (body as { on?: (event: string, handler: () => void) => void }).on === \"function\"\n\t) {\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst stream = body as {\n\t\t\t\tresume: () => void;\n\t\t\t\ton: (event: string, handler: () => void) => void;\n\t\t\t};\n\t\t\tconst finish = () => resolve();\n\t\t\tstream.on(\"end\", finish);\n\t\t\tstream.on(\"error\", finish);\n\t\t\tstream.resume();\n\t\t});\n\t}\n}\n\nfunction buildDiagnosticDetails(message: string, responseBody: ResponseBodyDiagnostics): string {\n\tconst detailParts = [message];\n\n\tif (responseBody.contentType) {\n\t\tdetailParts.push(`Content-Type: ${responseBody.contentType}.`);\n\t}\n\n\tif (responseBody.jsonParseError) {\n\t\tdetailParts.push(`JSON parse error: ${responseBody.jsonParseError.message}.`);\n\t}\n\n\tif (responseBody.bodyText) {\n\t\tdetailParts.push(\"The raw response body is available in bodyText.\");\n\t}\n\n\treturn detailParts.join(\" \");\n}\n\nfunction isJsonContentType(contentType?: string): boolean {\n\tif (!contentType) {\n\t\treturn false;\n\t}\n\n\tconst mimeType = contentType.split(\";\")[0]?.trim().toLowerCase();\n\tif (!mimeType) {\n\t\treturn false;\n\t}\n\n\treturn mimeType === \"application/json\" || mimeType.endsWith(\"+json\");\n}\n\nfunction truncateBody(bodyText: string): string | undefined {\n\tif (bodyText.length === 0) {\n\t\treturn undefined;\n\t}\n\n\tif (bodyText.length <= MAX_DIAGNOSTIC_BODY_LENGTH) {\n\t\treturn bodyText;\n\t}\n\n\treturn `${bodyText.slice(0, MAX_DIAGNOSTIC_BODY_LENGTH - 3)}...`;\n}\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tconst message = typeof error === \"string\" && error.length > 0 ? error : \"Unknown error\";\n\treturn new Error(message);\n}\n","import type { z, ZodTypeAny } from \"zod\";\nimport type { ApiGatewayError } from \"../errors\";\nimport { ApiServiceError } from \"../errors\";\nimport { createGatewayError, createUnexpectedServiceResponseError } from \"./error-factories\";\nimport {\n\tdescribeGatewayResponse,\n\tdescribeUnexpectedSuccessResponse,\n\tgetResponseContentType,\n\tgetResponseRequestId,\n\tisGatewayStatusCode,\n\tparseApiErrorResponse,\n\tparseApiResponse,\n\treadResponseBody,\n\ttype ResponseBodyDiagnostics,\n} from \"./response-handling\";\n\n/**\n * Validates an outbound request body when the caller supplied a schema.\n *\n * Requests without a body, or without a schema, pass through unchanged.\n */\nexport function parseRequestBody<ReqSchema extends ZodTypeAny | undefined>(\n\trequestSchema: ReqSchema | undefined,\n\tbody: (ReqSchema extends ZodTypeAny ? z.infer<ReqSchema> : unknown) | undefined,\n): (ReqSchema extends ZodTypeAny ? z.infer<ReqSchema> : unknown) | undefined {\n\tif (!requestSchema || body === undefined) {\n\t\treturn body;\n\t}\n\n\treturn requestSchema.parse(body);\n}\n\n/**\n * Consumes the HTTP response body and converts body-read failures into the same\n * client error model used for normal gateway and service failures.\n */\nexport async function readApiResponseBody(\n\tpath: string,\n\turl: string,\n\tresponse: Response,\n): Promise<ResponseBodyDiagnostics> {\n\ttry {\n\t\treturn await readResponseBody(response);\n\t} catch (error) {\n\t\tif (response.ok) {\n\t\t\tthrow createUnexpectedServiceResponseError(path, url, {\n\t\t\t\tcontentType: getResponseContentType(response),\n\t\t\t\tcause: error,\n\t\t\t\tdetails: \"Failed to read the response body before the API response could be validated.\",\n\t\t\t\trequestId: getResponseRequestId(response),\n\t\t\t});\n\t\t}\n\n\t\tthrow createGatewayError(path, url, response.status, {\n\t\t\tcontentType: getResponseContentType(response),\n\t\t\tcause: error,\n\t\t\tdetails:\n\t\t\t\t\"Failed to read the non-success response body, so the response could not be validated as a service error.\",\n\t\t\trequestId: getResponseRequestId(response),\n\t\t});\n\t}\n}\n\n/**\n * Interprets a successful HTTP response as either a valid Content Curation API\n * success envelope or a service-origin failure.\n */\nexport function parseSuccessfulResponse<ResponseDataSchema extends ZodTypeAny>(\n\tpath: string,\n\turl: string,\n\tresponse: Response,\n\tresponseBody: ResponseBodyDiagnostics,\n\tresponseDataSchema: ResponseDataSchema,\n): z.infer<ResponseDataSchema> {\n\tconst parsedResponse = parseApiResponse(responseDataSchema, responseBody);\n\n\tif (!parsedResponse) {\n\t\tthrow createUnexpectedServiceResponseError(path, url, {\n\t\t\tcontentType: responseBody.contentType,\n\t\t\tbodyText: responseBody.bodyText,\n\t\t\tdetails: describeUnexpectedSuccessResponse(responseBody),\n\t\t\trequestId: getResponseRequestId(response),\n\t\t});\n\t}\n\n\tif (\"error\" in parsedResponse) {\n\t\tthrow new ApiServiceError(\n\t\t\tparsedResponse.error,\n\t\t\tparsedResponse.statusCode,\n\t\t\tparsedResponse.requestId,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tcontentType: responseBody.contentType,\n\t\t\t\tbodyText: responseBody.bodyText,\n\t\t\t},\n\t\t);\n\t}\n\n\treturn parsedResponse.data;\n}\n\n/**\n * Classifies a non-success HTTP response as either a validated service error or\n * a gateway-origin failure.\n */\nexport function createResponseError(\n\tpath: string,\n\turl: string,\n\tresponse: Response,\n\tresponseBody: ResponseBodyDiagnostics,\n): ApiGatewayError | ApiServiceError {\n\tif (isGatewayStatusCode(response.status)) {\n\t\treturn createGatewayError(path, url, response.status, {\n\t\t\tcontentType: responseBody.contentType,\n\t\t\tbodyText: responseBody.bodyText,\n\t\t\tdetails: describeGatewayResponse(response.status, responseBody),\n\t\t\trequestId: getResponseRequestId(response),\n\t\t});\n\t}\n\n\tconst parsedServiceError = parseApiErrorResponse(responseBody);\n\tif (parsedServiceError) {\n\t\treturn new ApiServiceError(\n\t\t\tparsedServiceError.error,\n\t\t\tparsedServiceError.statusCode,\n\t\t\tparsedServiceError.requestId,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tcontentType: responseBody.contentType,\n\t\t\t\tbodyText: responseBody.bodyText,\n\t\t\t},\n\t\t);\n\t}\n\n\treturn createGatewayError(path, url, response.status, {\n\t\tcontentType: responseBody.contentType,\n\t\tbodyText: responseBody.bodyText,\n\t\tdetails: describeGatewayResponse(response.status, responseBody),\n\t\trequestId: getResponseRequestId(response),\n\t});\n}\n","import type { z, ZodTypeAny } from \"zod\";\nimport {\n\tcreateResponseError,\n\tcreateTransportError,\n\tparseRequestBody,\n\tparseSuccessfulResponse,\n\treadApiResponseBody,\n} from \"./internal\";\n\n/**\n * Configuration options for the API client.\n */\nexport type ApiClientConfig =\n\t| {\n\t\t\t// Standard configuration.\n\t\t\t// Intended for external clients using an API key issued via API Gateway.\n\t\t\tbaseUrl: string;\n\t\t\tapiKey: string;\n\t\t\tapiToken?: never;\n\t\t\tfetch?: typeof fetch;\n\t }\n\t| {\n\t\t\t// Alternative configuration.\n\t\t\t// Reserved for clients with access to a bearer token (for example, e2e tests).\n\t\t\tbaseUrl: string;\n\t\t\tapiKey?: never;\n\t\t\tapiToken: string;\n\t\t\tfetch?: typeof fetch;\n\t };\n\n/**\n * Shared HTTP client for Content Curation API requests.\n *\n * The public sub-clients delegate to this class so request validation, fetch\n * execution, response parsing, and error classification all happen in one place.\n */\nexport class BaseApiClient {\n\tprotected config: ApiClientConfig;\n\n\tconstructor(config: ApiClientConfig) {\n\t\tthis.config = {\n\t\t\t...config,\n\t\t\tfetch: config.fetch || fetch,\n\t\t};\n\t\tthis.config.baseUrl = trimTrailingSlashes(this.config.baseUrl);\n\t}\n\n\t/**\n\t * Performs a request against the JSON API, validates the response envelope,\n\t * and returns the typed `data` payload on success.\n\t */\n\tprotected async request<\n\t\tReqSchema extends ZodTypeAny | undefined,\n\t\tResponseDataSchema extends ZodTypeAny,\n\t>(\n\t\tmethod: \"GET\" | \"PUT\" | \"POST\" | \"DELETE\",\n\t\tpath: string,\n\t\topts: {\n\t\t\trequestSchema?: ReqSchema;\n\t\t\tbody?: ReqSchema extends ZodTypeAny ? z.infer<ReqSchema> : unknown;\n\t\t\tresponseDataSchema: ResponseDataSchema;\n\t\t},\n\t): Promise<z.infer<ResponseDataSchema>> {\n\t\tconst bodyPayload = parseRequestBody(opts.requestSchema, opts.body);\n\t\tconst urlString = new URL(this.config.baseUrl + path).toString();\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await this.config.fetch!(urlString, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t...(this.config.apiKey\n\t\t\t\t\t\t? { \"x-api-key\": this.config.apiKey }\n\t\t\t\t\t\t: { Authorization: `Bearer ${this.config.apiToken}` }),\n\t\t\t\t},\n\t\t\t\tbody: bodyPayload === undefined ? undefined : JSON.stringify(bodyPayload),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow createTransportError(path, urlString, error);\n\t\t}\n\n\t\tconst responseBody = await readApiResponseBody(path, urlString, response);\n\n\t\tif (response.ok) {\n\t\t\treturn parseSuccessfulResponse(\n\t\t\t\tpath,\n\t\t\t\turlString,\n\t\t\t\tresponse,\n\t\t\t\tresponseBody,\n\t\t\t\topts.responseDataSchema,\n\t\t\t);\n\t\t}\n\n\t\tthrow createResponseError(path, urlString, response, responseBody);\n\t}\n\n\t/**\n\t * GET convenience method inferring response type from schema.\n\t */\n\tprotected get<ResponseDataSchema extends ZodTypeAny>(\n\t\tpath: string,\n\t\tresponseDataSchema: ResponseDataSchema,\n\t): Promise<z.infer<ResponseDataSchema>> {\n\t\treturn this.request(\"GET\", path, { responseDataSchema });\n\t}\n\n\t/**\n\t * PUT convenience method inferring both request and response types.\n\t */\n\tprotected put<ReqSchema extends ZodTypeAny, ResponseDataSchema extends ZodTypeAny>(\n\t\tpath: string,\n\t\tbody: z.infer<ReqSchema>,\n\t\trequestSchema: ReqSchema,\n\t\tresponseDataSchema: ResponseDataSchema,\n\t): Promise<z.infer<ResponseDataSchema>> {\n\t\treturn this.request(\"PUT\", path, { body, requestSchema, responseDataSchema });\n\t}\n}\n\nfunction trimTrailingSlashes(value: string): string {\n\tlet end = value.length;\n\n\twhile (end > 0 && value.charCodeAt(end - 1) === 47) {\n\t\tend -= 1;\n\t}\n\n\treturn end === value.length ? value : value.slice(0, end);\n}\n","import { z } from \"zod\";\nimport { ProseMirrorDocSchema } from \"../../prosemirror\";\n\n//\n// 1) REUSABLE SCHEMAS FOR COMMON STRUCTURES\n//\n\n/**\n * A generic schema representing a heading used across various slices.\n * - `text`: The display text of the heading.\n * - `href`: An optional URL that the heading links to.\n */\nconst HeadingSchema = z.object({\n\ttext: z.string(),\n\thref: z.string().url().optional(),\n});\n\n/**\n * Base “properties” common to most page slices.\n * - `heading`: An optional heading object for slices that can display a title.\n */\nconst BasePageItemProps = z.object({\n\theading: HeadingSchema.optional(),\n});\n\n/**\n * A schema to validate that a string is valid JSON.\n */\nconst ValidJSONStringSchema = z.string().refine(\n\t(val) => {\n\t\ttry {\n\t\t\tJSON.parse(val);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n\t{ message: \"Invalid JSON string\" },\n);\n\n//\n// 2) GENERIC HELPER TO DEFINE “SLICE” INPUT/OUTPUT SCHEMAS\n//\n\n/**\n * A union type to represent either a Zod object schema or an optional Zod object schema.\n */\ntype OptionalOrRequiredZodObject = z.AnyZodObject | z.ZodOptional<z.AnyZodObject>;\n\n/**\n * Helper function that, given:\n * - `typeName`: A string literal identifying the slice type.\n * - `propsShape`: A Zod schema describing the slice’s `properties`.\n *\n * Returns an object containing two schemas:\n * - `InputSchema`: For client-side input; `sliceId` is optional.\n * - `OutputSchema`: For server-side/output; `sliceId` is required.\n *\n * This is useful because when defining slices we often want to allow -\n * clients to submit slices without an ID (e.g., when creating new slices),\n */\nfunction defineSliceSchema<T extends string, P extends OptionalOrRequiredZodObject>(options: {\n\ttypeName: T;\n\tpropsShape: P;\n}) {\n\tconst { typeName, propsShape } = options;\n\n\t// Base schema shared by both input and output:\n\t// - `type`: Literal string identifying which slice this is.\n\t// - `hidden`: Optional flag to mark the slice as hidden.\n\t// - `properties`: The detailed properties shape for the slice.\n\tconst BaseSchema = z.object({\n\t\ttype: z.literal(typeName),\n\t\thidden: z.boolean().optional(),\n\t\tproperties: propsShape,\n\t});\n\n\t/**\n\t * Input schema: For client submissions.\n\t * - `sliceId` is optional because the client might not specify it yet.\n\t */\n\tconst InputSchema = BaseSchema.extend({\n\t\tsliceId: z.string().uuid().optional(),\n\t});\n\n\t/**\n\t * Output schema: For persisted or server-returned data.\n\t * - `sliceId` is required (each saved slice must have an ID).\n\t */\n\tconst OutputSchema = BaseSchema.extend({\n\t\tsliceId: z.string().uuid(),\n\t});\n\n\treturn { InputSchema, OutputSchema };\n}\n\n//\n// 3) DEFINE INDIVIDUAL SLICE TYPES (INPUT & OUTPUT) USING THE HELPER\n//\n\n// 3.A “HomepageSlice”\n// - A generic homepage slice that may include an optional heading.\n// - Input: Clients can pass `properties` or omit entirely.\n// - Output: Always includes a `properties` object (may be empty) and a required `sliceId`.\nconst HomepageSlice = defineSliceSchema({\n\ttypeName: \"HomepageSlice\",\n\tpropsShape: BasePageItemProps.optional(),\n});\n\n// 3.B “InteractiveSlice”\n// - A slice to embed or reference a Flourish graphic by its ID.\n// - Extends graphic base properties with `flourishId` and `flourishAltText`, with optional 'theme', 'flourishDescription' or 'storyUUID'.\nconst InteractiveSlice = defineSliceSchema({\n\ttypeName: \"Interactive\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tflourishDescription: z.string().optional(), // Optional description for the Flourish graphic\n\t\tflourishId: z.string().nonempty(),\n\t\tflourishAltText: z.string().nonempty(),\n\t\tstoryUUID: z.string().uuid().optional(),\n\t\ttheme: z.string().optional(),\n\t}),\n});\n\n// 3.C “ExperimentSlice”\n// - A slice for embedding experimental content.\n// - Requires an `experimentId`, `experimentName`, and a JSON string (`contentJson`).\nconst ExperimentSlice = defineSliceSchema({\n\ttypeName: \"Experiment\",\n\tpropsShape: BasePageItemProps.extend({\n\t\texperimentId: z.string().nonempty(), // Unique ID for the experiment\n\t\texperimentName: z.string().nonempty(), // Human-readable name of the experiment\n\t\tcontentJson: ValidJSONStringSchema, // The experiment’s JSON payload as a valid JSON string\n\t}),\n});\n\n// 3.D \"Strip\"\n// - A slice that displays a strip of content.\nconst StripSlice = defineSliceSchema({\n\ttypeName: \"Strip\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tlistId: z.string().uuid(), // The ID of the strip to display\n\t\tmaxStories: z.number().int().min(1).max(20), // Maximum number of stories to display in the strip\n\t}),\n});\n\n// 3.E \"TopperSlice\"\n// - A slice that displays a topper section with description and optional strapline.\nconst TopperSlice = defineSliceSchema({\n\ttypeName: \"Topper\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tdescription: ProseMirrorDocSchema,\n\t\tstrapline: z.string().optional(),\n\t}),\n});\n\n// 3.F \"Hero\"\n// - A slice that represents a Hero on the page. It references a Spark List.\nconst HeroSlice = defineSliceSchema({\n\ttypeName: \"Hero\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tlistId: z.string().uuid(), // The ID of the spark list to display\n\t\tmaxStories: z.number().int().min(1).max(20), // Maximum number of stories to display in the hero\n\t}),\n});\n\n// 3.G \"StoryGroup\"\n// - A slice that stores an ordered list of manually curated content ids.\nconst StoryGroupSlice = defineSliceSchema({\n\ttypeName: \"StoryGroup\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tstorySlots: z.array(z.string().uuid()).nonempty(),\n\t}),\n});\n\n//\n// 4) COMPOSE DISCRIMINATED UNIONS FOR “SLICE API” INPUT & OUTPUT\n//\n\n/**\n * All possible slice inputs for the Page API.\n * This discriminated union allows Zod to pick the correct schema based on the `type` field.\n */\nexport const SliceApiInputSchema = z.discriminatedUnion(\"type\", [\n\tHomepageSlice.InputSchema,\n\tInteractiveSlice.InputSchema,\n\tExperimentSlice.InputSchema,\n\tStripSlice.InputSchema,\n\tTopperSlice.InputSchema,\n\tHeroSlice.InputSchema,\n\tStoryGroupSlice.InputSchema,\n] as const);\n\n/**\n * All possible slice outputs for the Page API.\n * The same discriminated union but with each slice requiring `sliceId`.\n */\nexport const SliceApiOutputSchema = z.discriminatedUnion(\"type\", [\n\tHomepageSlice.OutputSchema,\n\tInteractiveSlice.OutputSchema,\n\tExperimentSlice.OutputSchema,\n\tStripSlice.OutputSchema,\n\tTopperSlice.OutputSchema,\n\tHeroSlice.OutputSchema,\n\tStoryGroupSlice.OutputSchema,\n] as const);\n\n//\n// 5) WRAPPER SCHEMAS FOR THE ENTIRE PAGE STRUCTURE\n//\n\nconst BasePagePropertiesSchema = z.object({\n\ttitle: z.string(),\n\tpageId: z.string().uuid(),\n\tpublicationId: z.string(),\n\tconceptId: z.string().uuid().optional(),\n\tmetaDescription: z.string().optional(),\n\tpageTheme: z.string().optional(),\n\tsponsorText: z.string().optional(),\n\tsponsorImage: z.string().url().optional(),\n});\n\n/**\n * Page structure as submitted by clients.\n * - `properties`: Metadata about the page\n * - `children`: Array of slice inputs (each with an optional `sliceId`).\n */\nexport const PageStructureInputSchema = z.object({\n\tproperties: BasePagePropertiesSchema,\n\tchildren: z.array(SliceApiInputSchema),\n});\n\n/**\n * Page structure as submitted by clients.\n * - `properties`: Metadata about the page (title, list ID, page ID).\n * - `children`: Array of slice inputs (each with an optional `sliceId`).\n */\nexport const HomepageStructureInputSchema = PageStructureInputSchema.extend({\n\tproperties: BasePagePropertiesSchema.extend({\n\t\t// This is optional for the input. If clients don't send it, we generate a uuid.\n\t\thomepageListId: z.string().uuid(),\n\t}),\n});\n\n/**\n * Page structure as stored or returned by the server.\n */\nexport const PageStructureOutputSchema = z.object({\n\ttype: z.literal(\"Page\"),\n\tschemaVersion: z.number(),\n\tproperties: BasePagePropertiesSchema,\n\tchildren: z.array(SliceApiOutputSchema),\n});\n\nexport const HomepageStructureOutputSchema = PageStructureOutputSchema.extend({\n\ttype: z.literal(\"Homepage\"),\n\tproperties: BasePagePropertiesSchema.extend({\n\t\thomepageListId: z.string().uuid(),\n\t}),\n});\n\n//\n// 6) EXPORT TYPES FOR CONSUMPTION IN CODE\n//\n\n/** Client-side type for page structure input */\nexport type PageStructureInput = z.infer<typeof PageStructureInputSchema>;\n\n/** Server-side type for page structure output */\nexport type PageStructureOutput = z.infer<typeof PageStructureOutputSchema>;\n\n/** Client-side type for homepage structure input */\nexport type HomepageStructureInput = z.infer<typeof HomepageStructureInputSchema>;\n\n/** Server-side type for homepage structure output */\nexport type HomepageStructureOutput = z.infer<typeof HomepageStructureOutputSchema>;\n\n/** Union of all possible slice outputs for type-checking convenience */\nexport type Slice = z.infer<typeof SliceApiOutputSchema>;\n\n/** Individual slice output types */\nexport type HomepageSliceType = z.infer<typeof HomepageSlice.OutputSchema>;\nexport type InteractiveSliceType = z.infer<typeof InteractiveSlice.OutputSchema>;\nexport type ExperimentSliceType = z.infer<typeof ExperimentSlice.OutputSchema>;\nexport type StripSliceType = z.infer<typeof StripSlice.OutputSchema>;\nexport type TopperSliceType = z.infer<typeof TopperSlice.OutputSchema>;\nexport type HeroSliceType = z.infer<typeof HeroSlice.OutputSchema>;\nexport type StoryGroupSliceType = z.infer<typeof StoryGroupSlice.OutputSchema>;\n","import { z } from \"zod\";\n\n/** Accept http(s) and mailto: (matches your editor config) */\nconst HrefSchema = z.string().refine((v) => /^(https?:\\/\\/|mailto:).+/.test(v), {\n\tmessage: \"Expected http(s):// or mailto: URL\",\n});\n\n/** Link mark. */\nconst ProseMirrorLinkMark = z.object({\n\ttype: z.literal(\"link\"),\n\tattrs: z.object({\n\t\thref: HrefSchema,\n\t}),\n});\n\n/** Supported text marks */\nconst ProseMirrorMark = z.discriminatedUnion(\"type\", [\n\tProseMirrorLinkMark,\n\tz.object({ type: z.literal(\"bold\") }),\n\tz.object({ type: z.literal(\"italic\") }),\n\tz.object({ type: z.literal(\"underline\") }),\n\tz.object({ type: z.literal(\"strike\") }),\n]);\n\n/** Text node */\nconst ProseMirrorTextNode = z.object({\n\ttype: z.literal(\"text\"),\n\ttext: z.string(),\n\tmarks: z.array(ProseMirrorMark).optional(),\n});\n\n/** Paragraph node — content can be empty/omitted */\nconst ProseMirrorParagraphNode = z.object({\n\ttype: z.literal(\"paragraph\"),\n\tcontent: z.array(ProseMirrorTextNode),\n});\n\n/** ProseMirror Node Union. */\nconst ProseMirrorNode = z.union([ProseMirrorParagraphNode, ProseMirrorTextNode]);\n\n/** Root node of a ProseMirror document - enforcing at least 1 paragraph */\nexport const ProseMirrorDocSchema = z.object({\n\ttype: z.literal(\"doc\"),\n\tcontent: z\n\t\t.array(ProseMirrorNode)\n\t\t.min(1, { message: \"Document must contain at least one paragraph\" }),\n});\n\n/** Rich text editor TS type. */\nexport type RichTextEditorType = z.infer<typeof ProseMirrorDocSchema>;\n\nexport {};\n","import { BaseApiClient } from \"./base\";\nimport {\n\tHomepageStructureInputSchema,\n\tHomepageStructureOutputSchema,\n\ttype HomepageStructureInput,\n\ttype HomepageStructureOutput,\n} from \"./schemas/ftpink/page\";\n\n/**\n * Client for Homepage structure endpoints\n */\nexport class HomepageClient extends BaseApiClient {\n\tasync getStructure(pageId: string): Promise<HomepageStructureOutput> {\n\t\treturn this.get(`/v1/homepage/${pageId}/structure`, HomepageStructureOutputSchema);\n\t}\n\n\tasync getStructuresByHomepageListId(homepageListId: string): Promise<HomepageStructureOutput[]> {\n\t\treturn this.get(\n\t\t\t`/v1/homepage/list/${homepageListId}/structures`,\n\t\t\tHomepageStructureOutputSchema.array(),\n\t\t);\n\t}\n\n\tasync upsertStructure(\n\t\tpageId: string,\n\t\tdata: Omit<HomepageStructureInput, \"type\">,\n\t): Promise<HomepageStructureOutput> {\n\t\treturn this.put(\n\t\t\t`/v1/homepage/${pageId}/structure`,\n\t\t\tdata,\n\t\t\tHomepageStructureInputSchema,\n\t\t\tHomepageStructureOutputSchema,\n\t\t);\n\t}\n}\n","import { z } from \"zod\";\n\n/**\n * -----------------------------------------\n * Legacy API Schemas & Types\n *\n * These schemas map to expected types for Hub Pages rendered by dotcom-pages.\n * -----------------------------------------\n */\n\nconst LegacyFlourishChildSchema = z.object({\n\tsource: z.literal(\"flourish\"),\n\tproperties: z.object({\n\t\tid: z.string().min(1), // e.g. \"visualisation/21901162\"\n\t}),\n});\n\nconst LegacyListChildSchema = z.object({\n\tsource: z.literal(\"list\"),\n\tproperties: z.object({\n\t\tid: z.string().uuid(),\n\t\tmaxItems: z.number().optional(),\n\t}),\n});\n\nconst LegacyContentChildSchema = z.object({\n\tsource: z.literal(\"content\"),\n\tproperties: z.object({\n\t\tids: z.array(z.string()).nonempty(),\n\t}),\n});\n\nconst LegacyContainerChildSchema = z.discriminatedUnion(\"source\", [\n\tLegacyFlourishChildSchema,\n\tLegacyListChildSchema,\n\tLegacyContentChildSchema,\n]);\n\nconst LegacyTopperSchema = z.object({\n\ttype: z.literal(\"topper-basic\"),\n\tproperties: z.object({\n\t\ttitle: z.string(),\n\t\tsponsorText: z.string().optional(),\n\t\tsponsorImage: z.string().url().optional(),\n\t}),\n});\n\nconst LegacyInfoBoxSchema = z.object({\n\ttype: z.literal(\"info-box\"),\n\tproperties: z.object({\n\t\tbodyHTML: z.string(),\n\t\ttitle: z.string().optional(),\n\t}),\n});\n\nconst LegacyContainerSchema = z.object({\n\ttype: z.literal(\"container\"),\n\tchildren: z.array(LegacyContainerChildSchema).min(1),\n\tproperties: z.object({\n\t\ttitle: z.string().optional(),\n\t\tdesign: z.enum([\"chart\", \"four-story\", \"freeform\", \"hero-lead\"]).default(\"freeform\"),\n\t\tbackgroundColor: z.string().optional(),\n\t}),\n});\n\nconst LegacyExperimentSchema = z.object({\n\ttype: z.literal(\"experiment\"),\n\tchildren: z.tuple([]),\n\tproperties: z.object({\n\t\texperimentName: z.string(),\n\t\tid: z.string(),\n\t\ttitle: z.string().optional(),\n\t\tconfig: z\n\t\t\t.object({\n\t\t\t\tvalue: z.unknown().optional(),\n\t\t\t\t// Hub pages support experiments with HTML and Text.\n\t\t\t\t// For now we just support JSON. As we migrate pages, this may change.\n\t\t\t\tformat: z.enum([\"json\"]).default(\"json\"),\n\t\t\t})\n\t\t\t.partial()\n\t\t\t.optional(),\n\t}),\n});\n\nconst LegacyBlockSchema = z.discriminatedUnion(\"type\", [\n\tLegacyTopperSchema,\n\tLegacyInfoBoxSchema,\n\tLegacyContainerSchema,\n\tLegacyExperimentSchema,\n]);\n\nexport const LegacyPageStructureOutputSchema = z.object({\n\tuuid: z.string().uuid(),\n\ttitle: z.string(),\n\tconceptId: z.string().uuid().optional(),\n\tthemeName: z.string().optional(),\n\tmetaDescription: z.string().optional(),\n\tblocks: z.array(LegacyBlockSchema),\n});\n\nexport type LegacyPageStructureOutput = z.infer<typeof LegacyPageStructureOutputSchema>;\nexport type LegacyBlock = z.infer<typeof LegacyBlockSchema>;\n","import { z } from \"zod\";\nimport { PageStructureInputSchema, PageStructureOutputSchema } from \"../page\";\n\nexport const DraftContributorInputSchema = z.object({\n\tuserId: z.string().min(1),\n\tdisplayName: z.string().min(1),\n\temail: z.string().email().optional(),\n});\n\nexport const DraftContributorSchema = DraftContributorInputSchema.extend({\n\tuserId: z.string().min(1),\n\tdisplayName: z.string().min(1),\n\tfirstTouchedAt: z.string().datetime(),\n\tlastTouchedAt: z.string().datetime(),\n});\n\nconst DraftMetadataSchema = z.object({\n\tdraftId: z.string().uuid(),\n\tcreatedAt: z.string().datetime(),\n\tupdatedAt: z.string().datetime(),\n\tcontributors: z.array(DraftContributorSchema),\n});\n\nexport const PageDraftSchema = DraftMetadataSchema.extend({\n\tstructure: PageStructureOutputSchema,\n});\n\nexport const DraftSchema = PageDraftSchema;\n\nexport const PersistPageDraftInputSchema = z.object({\n\tstructure: PageStructureInputSchema,\n\tcontributor: DraftContributorInputSchema,\n});\n\nexport type DraftContributorInput = z.infer<typeof DraftContributorInputSchema>;\nexport type DraftContributor = z.infer<typeof DraftContributorSchema>;\nexport type PageDraft = z.infer<typeof PageDraftSchema>;\nexport type Draft = z.infer<typeof DraftSchema>;\nexport type PersistPageDraftInput = z.infer<typeof PersistPageDraftInputSchema>;\n","import { BaseApiClient } from \"./base\";\nimport { ApiServiceError } from \"./errors\";\nimport type { LegacyPageStructureOutput } from \"./schemas/ftpink/legacyHubPage\";\nimport { LegacyPageStructureOutputSchema } from \"./schemas/ftpink/legacyHubPage\";\nimport {\n\tPageStructureInputSchema,\n\tPageStructureOutputSchema,\n\ttype PageStructureInput,\n\ttype PageStructureOutput,\n} from \"./schemas/ftpink/page\";\nimport { PageDraftSchema, type PageDraft } from \"./schemas/ftpink/draft\";\n\n/**\n * Client for Page structure endpoints\n */\nexport class PageClient extends BaseApiClient {\n\tasync getStructure(pageId: string): Promise<PageStructureOutput> {\n\t\treturn this.get(`/v1/page/${pageId}/structure`, PageStructureOutputSchema);\n\t}\n\n\tasync getDraft(pageId: string): Promise<PageDraft | null> {\n\t\ttry {\n\t\t\treturn await this.get(`/v1/page/${pageId}/draft`, PageDraftSchema);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiServiceError && error.code === \"NOT_FOUND\") {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync getLegacyHubPageStructure(pageId: string): Promise<LegacyPageStructureOutput> {\n\t\treturn this.get(`/v1/page/${pageId}/legacyHubPageStructure`, LegacyPageStructureOutputSchema);\n\t}\n\n\tasync upsertStructure(\n\t\tpageId: string,\n\t\tdata: Omit<PageStructureInput, \"type\">,\n\t): Promise<PageStructureOutput> {\n\t\treturn this.put(\n\t\t\t`/v1/page/${pageId}/structure`,\n\t\t\tdata,\n\t\t\tPageStructureInputSchema,\n\t\t\tPageStructureOutputSchema,\n\t\t);\n\t}\n}\n","import type { ApiClientConfig } from \"./base\";\nimport { BaseApiClient } from \"./base\";\nimport { HomepageClient } from \"./homepage\";\nimport { PageClient } from \"./page\";\n\n/**\n * Main API client that provides access to all API endpoints\n */\nexport class ApiClient extends BaseApiClient {\n\t/**\n\t * Homepage API endpoints\n\t */\n\thomepage: HomepageClient;\n\tpage: PageClient;\n\n\tconstructor(config: ApiClientConfig) {\n\t\tsuper(config);\n\n\t\t// Initialize sub-clients\n\t\tthis.homepage = new HomepageClient(config);\n\t\tthis.page = new PageClient(config);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/circleci/repo/packages/content-curation-client/dist/index.cjs","../src/errors.ts","../src/internal/error-factories.ts","../src/schemas/response.ts","../src/internal/response-handling.ts","../src/internal/request-lifecycle.ts","../src/base.ts","../src/schemas/ftpink/legacyHubPage/index.ts","../src/schemas/ftpink/page/index.ts","../src/schemas/prosemirror.ts","../src/schemas/ftpink/draft/index.ts","../src/page.ts","../src/client.ts"],"names":["z"],"mappings":"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","file":"/home/circleci/repo/packages/content-curation-client/dist/index.cjs","sourcesContent":[null,"import type { ApiErrorPayload } from \"./schemas/response\";\n\n/** Where the failing request broke down. */\nexport type ApiClientErrorOrigin = \"transport\" | \"gateway\" | \"service\";\n\n/** The transport failure mode when no HTTP response was received. */\nexport type ApiTransportKind = \"abort\" | \"timeout\" | \"network\";\n\n/** Machine-readable codes exposed by the client error model. */\nexport type ApiClientErrorCode =\n\t| ApiErrorPayload[\"code\"]\n\t| \"API_GATEWAY_ERROR\"\n\t| \"API_TRANSPORT_ERROR\";\n\n/**\n * Shared error payload shape used by all client-generated errors.\n *\n * Service-origin errors use the validated `ApiErrorPayload` returned by the API.\n * Gateway and transport errors synthesize the same top-level fields so callers\n * can handle them consistently.\n */\nexport type ApiClientErrorPayload = {\n\tcode: ApiClientErrorCode;\n\tmessage: string;\n\tdetails?: string;\n\tpath?: string;\n\ttimestamp?: string;\n};\n\ntype ApiClientErrorMetadata = {\n\torigin: ApiClientErrorOrigin;\n\turl?: string;\n\tcontentType?: string;\n\tbodyText?: string;\n\tcause?: unknown;\n};\n\ntype ApiTransportErrorMetadata = Omit<ApiClientErrorMetadata, \"origin\"> & {\n\ttransportKind: ApiTransportKind;\n};\n\n/**\n * Base error type for all failures surfaced by the client package.\n */\nexport class ApiClientError extends Error {\n\t/** The machine-readable error payload exposed by the client. */\n\tpublic payload: ApiClientErrorPayload;\n\t/** The machine-readable error code. */\n\tpublic code: ApiClientErrorPayload[\"code\"];\n\t/** Additional diagnostic detail captured by the client. */\n\tpublic details?: string;\n\t/** The API path associated with the failing request. */\n\tpublic path?: string;\n\t/** Optional timestamp supplied by the upstream service. */\n\tpublic timestamp?: string;\n\t/** Indicates whether the failure originated from transport, gateway, or service handling. */\n\tpublic origin: ApiClientErrorOrigin;\n\t/** The fully qualified request URL, when available. */\n\tpublic url?: string;\n\t/** The response content type, when a response was received. */\n\tpublic contentType?: string;\n\t/** A truncated copy of the raw response body, when captured. */\n\tpublic bodyText?: string;\n\t/** The upstream request identifier, when available. */\n\tpublic requestId?: string;\n\t/** The HTTP status code reported by the service or gateway. */\n\tpublic statusCode: number;\n\t/** The underlying thrown error, if there was one. */\n\tpublic override cause?: unknown;\n\n\tconstructor(\n\t\tpayload: ApiClientErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId?: string,\n\t\tmetadata: ApiClientErrorMetadata = { origin: \"service\" },\n\t) {\n\t\tsuper(payload.message);\n\t\tthis.name = new.target.name;\n\t\tthis.payload = payload;\n\t\tthis.statusCode = statusCode;\n\t\tthis.requestId = requestId;\n\t\tthis.code = payload.code;\n\t\tthis.details = payload.details;\n\t\tthis.path = payload.path;\n\t\tthis.timestamp = payload.timestamp;\n\t\tthis.origin = metadata.origin;\n\t\tthis.url = metadata.url;\n\t\tthis.contentType = metadata.contentType;\n\t\tthis.bodyText = metadata.bodyText;\n\t\tthis.cause = metadata.cause;\n\t}\n}\n\n/**\n * Error raised when the request fails before any HTTP response is available.\n */\nexport class ApiTransportError extends ApiClientError {\n\tpublic override payload: ApiClientErrorPayload;\n\tpublic override origin: \"transport\";\n\t/** Whether the failure was caused by an abort, timeout, or generic network problem. */\n\tpublic transportKind: ApiTransportKind;\n\n\tconstructor(\n\t\tpayload: ApiClientErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId: string | undefined,\n\t\tmetadata: ApiTransportErrorMetadata,\n\t) {\n\t\tsuper(payload, statusCode, requestId, {\n\t\t\t...metadata,\n\t\t\torigin: \"transport\",\n\t\t});\n\t\tthis.payload = payload;\n\t\tthis.origin = \"transport\";\n\t\tthis.transportKind = metadata.transportKind;\n\t}\n}\n\n/**\n * Error raised when the request reached API Gateway but did not produce a\n * valid service-level error envelope.\n */\nexport class ApiGatewayError extends ApiClientError {\n\tpublic override payload: ApiClientErrorPayload;\n\tpublic override origin: \"gateway\";\n\n\tconstructor(\n\t\tpayload: ApiClientErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId?: string,\n\t\tmetadata: Omit<ApiClientErrorMetadata, \"origin\"> = {},\n\t) {\n\t\tsuper(payload, statusCode, requestId, {\n\t\t\t...metadata,\n\t\t\torigin: \"gateway\",\n\t\t});\n\t\tthis.payload = payload;\n\t\tthis.origin = \"gateway\";\n\t}\n}\n\n/**\n * Error raised when the root service returns a valid JSON API error envelope,\n * or when a successful response cannot be interpreted as the expected API\n * success envelope.\n */\nexport class ApiServiceError extends ApiClientError {\n\tpublic override payload: ApiErrorPayload;\n\tpublic override origin: \"service\";\n\n\tconstructor(\n\t\tpayload: ApiErrorPayload,\n\t\tstatusCode: number,\n\t\trequestId?: string,\n\t\tmetadata: Omit<ApiClientErrorMetadata, \"origin\"> = {},\n\t) {\n\t\tsuper(payload, statusCode, requestId, {\n\t\t\t...metadata,\n\t\t\torigin: \"service\",\n\t\t});\n\t\tthis.payload = payload;\n\t\tthis.origin = \"service\";\n\t}\n}\n","import {\n\tApiGatewayError,\n\tApiServiceError,\n\tApiTransportError,\n\ttype ApiTransportKind,\n} from \"../errors\";\n\ntype GatewayErrorOptions = {\n\tcontentType?: string;\n\tbodyText?: string;\n\tdetails: string;\n\trequestId?: string;\n\tcause?: unknown;\n};\n\ntype UnexpectedServiceResponseOptions = GatewayErrorOptions;\n\n/**\n * Wraps a fetch failure that happened before any response was available.\n */\nexport function createTransportError(path: string, url: string, error: unknown): ApiTransportError {\n\tconst transportKind = classifyTransportFailure(error);\n\tconst message = describeTransportFailure(transportKind);\n\tconst causeDetails = getErrorDiagnosticMessage(error);\n\tconst details = causeDetails ? `${message} Cause: ${causeDetails}` : message;\n\n\treturn new ApiTransportError(\n\t\t{\n\t\t\tcode: \"API_TRANSPORT_ERROR\",\n\t\t\tmessage,\n\t\t\tdetails,\n\t\t\tpath,\n\t\t},\n\t\t0,\n\t\tundefined,\n\t\t{\n\t\t\ttransportKind,\n\t\t\turl,\n\t\t\tcause: error,\n\t\t},\n\t);\n}\n\n/**\n * Builds a gateway-origin client error after the caller has already decided the response does not\n * represent a validated service error envelope.\n */\nexport function createGatewayError(\n\tpath: string,\n\turl: string,\n\tstatusCode: number,\n\toptions: GatewayErrorOptions,\n): ApiGatewayError {\n\treturn new ApiGatewayError(\n\t\t{\n\t\t\tcode: \"API_GATEWAY_ERROR\",\n\t\t\tmessage: `The API gateway responded with status ${statusCode}.`,\n\t\t\tdetails: options.details,\n\t\t\tpath,\n\t\t},\n\t\tstatusCode,\n\t\toptions.requestId,\n\t\t{\n\t\t\turl,\n\t\t\tcontentType: options.contentType,\n\t\t\tbodyText: options.bodyText,\n\t\t\tcause: options.cause,\n\t\t},\n\t);\n}\n\n/**\n * Builds the fallback service error used when a 2xx response cannot be interpreted as the\n * expected Content Curation API success envelope.\n */\nexport function createUnexpectedServiceResponseError(\n\tpath: string,\n\turl: string,\n\toptions: UnexpectedServiceResponseOptions,\n): ApiServiceError {\n\treturn new ApiServiceError(\n\t\t{\n\t\t\tcode: \"INTERNAL_SERVER_ERROR\",\n\t\t\tmessage: \"Unexpected API response format\",\n\t\t\tdetails: options.details,\n\t\t\tpath,\n\t\t},\n\t\t500,\n\t\toptions.requestId,\n\t\t{\n\t\t\turl,\n\t\t\tcontentType: options.contentType,\n\t\t\tbodyText: options.bodyText,\n\t\t\tcause: options.cause,\n\t\t},\n\t);\n}\n\nfunction classifyTransportFailure(error: unknown): ApiTransportKind {\n\tconst errorName = readStringProperty(error, \"name\");\n\n\tif (errorName === \"AbortError\") {\n\t\treturn \"abort\";\n\t}\n\n\tif (errorName === \"TimeoutError\") {\n\t\treturn \"timeout\";\n\t}\n\n\tif (errorName === \"FetchError\" && readStringProperty(error, \"type\") === \"request-timeout\") {\n\t\treturn \"timeout\";\n\t}\n\n\treturn \"network\";\n}\n\nfunction describeTransportFailure(transportKind: ApiTransportKind): string {\n\tif (transportKind === \"abort\") {\n\t\treturn \"The request was aborted before a response was received.\";\n\t}\n\n\tif (transportKind === \"timeout\") {\n\t\treturn \"The request timed out before a response was received.\";\n\t}\n\n\treturn \"The request failed before a response was received.\";\n}\n\nfunction getErrorDiagnosticMessage(error: unknown): string | undefined {\n\tconst diagnosticParts = [\n\t\treadCauseCode(error),\n\t\treadStringProperty(error, \"name\"),\n\t\treadStringProperty(error, \"message\"),\n\t].filter(\n\t\t(value, index, values): value is string => Boolean(value) && values.indexOf(value) === index,\n\t);\n\n\treturn diagnosticParts.length > 0 ? diagnosticParts.join(\": \") : undefined;\n}\n\nfunction readCauseCode(error: unknown): string | undefined {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn undefined;\n\t}\n\n\tconst directCode = readStringProperty(error, \"code\");\n\tif (directCode) {\n\t\treturn directCode;\n\t}\n\n\tconst cause = (error as { cause?: unknown }).cause;\n\treturn readStringProperty(cause, \"code\");\n}\n\nfunction readStringProperty(error: unknown, property: string): string | undefined {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn undefined;\n\t}\n\n\tconst value = (error as Record<string, unknown>)[property];\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n","import { z, type ZodTypeAny } from \"zod\";\n\n/**\n * Strongly‐typed enum for all possible API error codes.\n */\nexport const ApiErrorCode = z.enum([\n\t\"UNAUTHORIZED\",\n\t\"NOT_FOUND\",\n\t\"INTERNAL_SERVER_ERROR\",\n\t\"INVALID_INPUT_DATA\",\n]);\n\n/**\n * Fields shared by both success and error envelopes (but not the discriminant).\n */\nconst BaseEnvelopeFields = z.object({\n\tstatusCode: z.number(),\n\trequestId: z.string(),\n});\n\n/**\n * Specific details carried in an error payload.\n */\nexport const ApiErrorPayloadSchema = z\n\t.object({\n\t\tcode: ApiErrorCode,\n\t\tmessage: z.string(),\n\t\tdetails: z.string().optional(),\n\t\tpath: z.string().optional(),\n\t\ttimestamp: z.string().optional(),\n\t})\n\t.strict();\n\nexport type ApiErrorPayload = z.infer<typeof ApiErrorPayloadSchema>;\n\n/**\n * Full “envelope” when the API has failed.\n */\nexport const ApiErrorResponseSchema = BaseEnvelopeFields.extend({\n\tstatus: z.literal(\"error\"),\n\terror: ApiErrorPayloadSchema,\n}).strict();\n\nexport type ApiErrorResponse = z.infer<typeof ApiErrorResponseSchema>;\n\n/**\n * Schema for a successful API response, given some data schema T.\n */\nexport function ApiSuccessResponseSchema<T extends ZodTypeAny>(dataSchema: T) {\n\treturn BaseEnvelopeFields.extend({\n\t\tstatus: z.literal(\"success\"),\n\t\tdata: dataSchema,\n\t}).strict();\n}\n\n/**\n * Union of success or error envelopes, discriminated on `status`.\n */\nexport function ApiResponseSchema<T extends ZodTypeAny>(dataSchema: T) {\n\tconst successSchema = ApiSuccessResponseSchema(dataSchema);\n\tconst errorSchema = ApiErrorResponseSchema;\n\treturn z.discriminatedUnion(\"status\", [successSchema, errorSchema]);\n}\n","import type { ZodTypeAny } from \"zod\";\nimport { ApiErrorResponseSchema, ApiResponseSchema } from \"../schemas/response\";\n\nconst GATEWAY_STATUS_CODES = new Set([499, 502, 503]);\nconst MAX_DIAGNOSTIC_BODY_LENGTH = 2000;\n\n/**\n * Captured information from a response body after the client has consumed it exactly once.\n */\nexport type ResponseBodyDiagnostics = {\n\tcontentType?: string;\n\tbodyText?: string;\n\tjson?: unknown;\n\tjsonParseError?: Error;\n};\n\n/**\n * Returns `true` when a status code should always be treated as an API Gateway failure.\n */\nexport function isGatewayStatusCode(statusCode: number): boolean {\n\treturn GATEWAY_STATUS_CODES.has(statusCode);\n}\n\n/**\n * Extracts the response content type, if one was provided.\n */\nexport function getResponseContentType(response: Response): string | undefined {\n\treturn response.headers?.get(\"content-type\") ?? undefined;\n}\n\n/**\n * Extracts the upstream request identifier, if one was provided.\n */\nexport function getResponseRequestId(response: Response): string | undefined {\n\treturn response.headers?.get(\"x-request-id\") ?? response.headers?.get(\"request-id\") ?? undefined;\n}\n\n/**\n * Reads a response body exactly once, truncates diagnostic text, and only parses JSON when the\n * declared content type says that is appropriate.\n */\nexport async function readResponseBody(response: Response): Promise<ResponseBodyDiagnostics> {\n\tconst contentType = getResponseContentType(response);\n\tlet rawBody = \"\";\n\n\ttry {\n\t\trawBody = await response.text();\n\t} catch (error) {\n\t\tawait discardResponseBody(response);\n\t\tthrow error;\n\t}\n\n\tconst bodyText = truncateBody(rawBody);\n\n\tif (!isJsonContentType(contentType) || rawBody.length === 0) {\n\t\treturn {\n\t\t\tcontentType,\n\t\t\tbodyText,\n\t\t};\n\t}\n\n\ttry {\n\t\treturn {\n\t\t\tcontentType,\n\t\t\tbodyText,\n\t\t\tjson: JSON.parse(rawBody),\n\t\t};\n\t} catch (error) {\n\t\treturn {\n\t\t\tcontentType,\n\t\t\tbodyText,\n\t\t\tjsonParseError: toError(error),\n\t\t};\n\t}\n}\n\n/**\n * Attempts to validate a consumed response body as a success-or-error API envelope.\n */\nexport function parseApiResponse<ResponseDataSchema extends ZodTypeAny>(\n\tresponseDataSchema: ResponseDataSchema,\n\tresponseBody: ResponseBodyDiagnostics,\n) {\n\tif (responseBody.json === undefined) {\n\t\treturn null;\n\t}\n\n\tconst parsedResponse = ApiResponseSchema(responseDataSchema).safeParse(responseBody.json);\n\treturn parsedResponse.success ? parsedResponse.data : null;\n}\n\n/**\n * Attempts to validate a consumed response body as a service-level error envelope.\n */\nexport function parseApiErrorResponse(responseBody: ResponseBodyDiagnostics) {\n\tif (responseBody.json === undefined) {\n\t\treturn null;\n\t}\n\n\tconst parsedError = ApiErrorResponseSchema.safeParse(responseBody.json);\n\treturn parsedError.success ? parsedError.data : null;\n}\n\n/**\n * Builds the diagnostic detail string used when a 2xx response cannot be understood as the\n * expected Content Curation API success envelope.\n */\nexport function describeUnexpectedSuccessResponse(responseBody: ResponseBodyDiagnostics): string {\n\tif (responseBody.jsonParseError) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t\"The service reported a JSON response but the body could not be parsed as JSON.\",\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\tif (!responseBody.contentType || !isJsonContentType(responseBody.contentType)) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t\"The service returned a success status without a JSON response body.\",\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\treturn buildDiagnosticDetails(\n\t\t\"The service returned JSON, but it did not match the expected Content Curation API envelope.\",\n\t\tresponseBody,\n\t);\n}\n\n/**\n * Builds the diagnostic detail string used when a non-success response should be treated as a\n * gateway-origin failure rather than a validated service error.\n */\nexport function describeGatewayResponse(\n\tstatusCode: number,\n\tresponseBody: ResponseBodyDiagnostics,\n): string {\n\tif (responseBody.jsonParseError) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t`The non-success response with status ${statusCode} declared a JSON content type, but its body could not be parsed as JSON.`,\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\tif (!responseBody.contentType || !isJsonContentType(responseBody.contentType)) {\n\t\treturn buildDiagnosticDetails(\n\t\t\t`The non-success response with status ${statusCode} was not a valid service JSON error envelope.`,\n\t\t\tresponseBody,\n\t\t);\n\t}\n\n\treturn buildDiagnosticDetails(\n\t\t`The non-success response with status ${statusCode} returned JSON, but it did not match the service error envelope.`,\n\t\tresponseBody,\n\t);\n}\n\n/**\n * Best-effort response cleanup for the rare case where reading the body throws before completion.\n */\nasync function discardResponseBody(response: Response): Promise<void> {\n\tconst body = response.body as unknown;\n\tif (!body) {\n\t\treturn;\n\t}\n\n\tif (typeof (body as { cancel?: () => Promise<void> }).cancel === \"function\") {\n\t\ttry {\n\t\t\tawait (body as { cancel: () => Promise<void> }).cancel();\n\t\t\treturn;\n\t\t} catch {\n\t\t\t// Best effort only.\n\t\t}\n\t}\n\n\tif (\n\t\ttypeof (body as { resume?: () => void }).resume === \"function\" &&\n\t\ttypeof (body as { on?: (event: string, handler: () => void) => void }).on === \"function\"\n\t) {\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst stream = body as {\n\t\t\t\tresume: () => void;\n\t\t\t\ton: (event: string, handler: () => void) => void;\n\t\t\t};\n\t\t\tconst finish = () => resolve();\n\t\t\tstream.on(\"end\", finish);\n\t\t\tstream.on(\"error\", finish);\n\t\t\tstream.resume();\n\t\t});\n\t}\n}\n\nfunction buildDiagnosticDetails(message: string, responseBody: ResponseBodyDiagnostics): string {\n\tconst detailParts = [message];\n\n\tif (responseBody.contentType) {\n\t\tdetailParts.push(`Content-Type: ${responseBody.contentType}.`);\n\t}\n\n\tif (responseBody.jsonParseError) {\n\t\tdetailParts.push(`JSON parse error: ${responseBody.jsonParseError.message}.`);\n\t}\n\n\tif (responseBody.bodyText) {\n\t\tdetailParts.push(\"The raw response body is available in bodyText.\");\n\t}\n\n\treturn detailParts.join(\" \");\n}\n\nfunction isJsonContentType(contentType?: string): boolean {\n\tif (!contentType) {\n\t\treturn false;\n\t}\n\n\tconst mimeType = contentType.split(\";\")[0]?.trim().toLowerCase();\n\tif (!mimeType) {\n\t\treturn false;\n\t}\n\n\treturn mimeType === \"application/json\" || mimeType.endsWith(\"+json\");\n}\n\nfunction truncateBody(bodyText: string): string | undefined {\n\tif (bodyText.length === 0) {\n\t\treturn undefined;\n\t}\n\n\tif (bodyText.length <= MAX_DIAGNOSTIC_BODY_LENGTH) {\n\t\treturn bodyText;\n\t}\n\n\treturn `${bodyText.slice(0, MAX_DIAGNOSTIC_BODY_LENGTH - 3)}...`;\n}\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tconst message = typeof error === \"string\" && error.length > 0 ? error : \"Unknown error\";\n\treturn new Error(message);\n}\n","import type { z, ZodTypeAny } from \"zod\";\nimport type { ApiGatewayError } from \"../errors\";\nimport { ApiServiceError } from \"../errors\";\nimport { createGatewayError, createUnexpectedServiceResponseError } from \"./error-factories\";\nimport {\n\tdescribeGatewayResponse,\n\tdescribeUnexpectedSuccessResponse,\n\tgetResponseContentType,\n\tgetResponseRequestId,\n\tisGatewayStatusCode,\n\tparseApiErrorResponse,\n\tparseApiResponse,\n\treadResponseBody,\n\ttype ResponseBodyDiagnostics,\n} from \"./response-handling\";\n\n/**\n * Validates an outbound request body when the caller supplied a schema.\n *\n * Requests without a body, or without a schema, pass through unchanged.\n */\nexport function parseRequestBody<ReqSchema extends ZodTypeAny | undefined>(\n\trequestSchema: ReqSchema | undefined,\n\tbody: (ReqSchema extends ZodTypeAny ? z.infer<ReqSchema> : unknown) | undefined,\n): (ReqSchema extends ZodTypeAny ? z.infer<ReqSchema> : unknown) | undefined {\n\tif (!requestSchema || body === undefined) {\n\t\treturn body;\n\t}\n\n\treturn requestSchema.parse(body);\n}\n\n/**\n * Consumes the HTTP response body and converts body-read failures into the same\n * client error model used for normal gateway and service failures.\n */\nexport async function readApiResponseBody(\n\tpath: string,\n\turl: string,\n\tresponse: Response,\n): Promise<ResponseBodyDiagnostics> {\n\ttry {\n\t\treturn await readResponseBody(response);\n\t} catch (error) {\n\t\tif (response.ok) {\n\t\t\tthrow createUnexpectedServiceResponseError(path, url, {\n\t\t\t\tcontentType: getResponseContentType(response),\n\t\t\t\tcause: error,\n\t\t\t\tdetails: \"Failed to read the response body before the API response could be validated.\",\n\t\t\t\trequestId: getResponseRequestId(response),\n\t\t\t});\n\t\t}\n\n\t\tthrow createGatewayError(path, url, response.status, {\n\t\t\tcontentType: getResponseContentType(response),\n\t\t\tcause: error,\n\t\t\tdetails:\n\t\t\t\t\"Failed to read the non-success response body, so the response could not be validated as a service error.\",\n\t\t\trequestId: getResponseRequestId(response),\n\t\t});\n\t}\n}\n\n/**\n * Interprets a successful HTTP response as either a valid Content Curation API\n * success envelope or a service-origin failure.\n */\nexport function parseSuccessfulResponse<ResponseDataSchema extends ZodTypeAny>(\n\tpath: string,\n\turl: string,\n\tresponse: Response,\n\tresponseBody: ResponseBodyDiagnostics,\n\tresponseDataSchema: ResponseDataSchema,\n): z.infer<ResponseDataSchema> {\n\tconst parsedResponse = parseApiResponse(responseDataSchema, responseBody);\n\n\tif (!parsedResponse) {\n\t\tthrow createUnexpectedServiceResponseError(path, url, {\n\t\t\tcontentType: responseBody.contentType,\n\t\t\tbodyText: responseBody.bodyText,\n\t\t\tdetails: describeUnexpectedSuccessResponse(responseBody),\n\t\t\trequestId: getResponseRequestId(response),\n\t\t});\n\t}\n\n\tif (\"error\" in parsedResponse) {\n\t\tthrow new ApiServiceError(\n\t\t\tparsedResponse.error,\n\t\t\tparsedResponse.statusCode,\n\t\t\tparsedResponse.requestId,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tcontentType: responseBody.contentType,\n\t\t\t\tbodyText: responseBody.bodyText,\n\t\t\t},\n\t\t);\n\t}\n\n\treturn parsedResponse.data;\n}\n\n/**\n * Classifies a non-success HTTP response as either a validated service error or\n * a gateway-origin failure.\n */\nexport function createResponseError(\n\tpath: string,\n\turl: string,\n\tresponse: Response,\n\tresponseBody: ResponseBodyDiagnostics,\n): ApiGatewayError | ApiServiceError {\n\tif (isGatewayStatusCode(response.status)) {\n\t\treturn createGatewayError(path, url, response.status, {\n\t\t\tcontentType: responseBody.contentType,\n\t\t\tbodyText: responseBody.bodyText,\n\t\t\tdetails: describeGatewayResponse(response.status, responseBody),\n\t\t\trequestId: getResponseRequestId(response),\n\t\t});\n\t}\n\n\tconst parsedServiceError = parseApiErrorResponse(responseBody);\n\tif (parsedServiceError) {\n\t\treturn new ApiServiceError(\n\t\t\tparsedServiceError.error,\n\t\t\tparsedServiceError.statusCode,\n\t\t\tparsedServiceError.requestId,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tcontentType: responseBody.contentType,\n\t\t\t\tbodyText: responseBody.bodyText,\n\t\t\t},\n\t\t);\n\t}\n\n\treturn createGatewayError(path, url, response.status, {\n\t\tcontentType: responseBody.contentType,\n\t\tbodyText: responseBody.bodyText,\n\t\tdetails: describeGatewayResponse(response.status, responseBody),\n\t\trequestId: getResponseRequestId(response),\n\t});\n}\n","import type { z, ZodTypeAny } from \"zod\";\nimport {\n\tcreateResponseError,\n\tcreateTransportError,\n\tparseRequestBody,\n\tparseSuccessfulResponse,\n\treadApiResponseBody,\n} from \"./internal\";\n\n/**\n * Configuration options for the API client.\n */\nexport type ApiClientConfig =\n\t| {\n\t\t\t// Standard configuration.\n\t\t\t// Intended for external clients using an API key issued via API Gateway.\n\t\t\tbaseUrl: string;\n\t\t\tapiKey: string;\n\t\t\tapiToken?: never;\n\t\t\tfetch?: typeof fetch;\n\t }\n\t| {\n\t\t\t// Alternative configuration.\n\t\t\t// Reserved for clients with access to a bearer token (for example, e2e tests).\n\t\t\tbaseUrl: string;\n\t\t\tapiKey?: never;\n\t\t\tapiToken: string;\n\t\t\tfetch?: typeof fetch;\n\t };\n\n/**\n * Shared HTTP client for Content Curation API requests.\n *\n * The public sub-clients delegate to this class so request validation, fetch\n * execution, response parsing, and error classification all happen in one place.\n */\nexport class BaseApiClient {\n\tprotected config: ApiClientConfig;\n\n\tconstructor(config: ApiClientConfig) {\n\t\tthis.config = {\n\t\t\t...config,\n\t\t\tfetch: config.fetch || fetch,\n\t\t};\n\t\tthis.config.baseUrl = trimTrailingSlashes(this.config.baseUrl);\n\t}\n\n\t/**\n\t * Performs a request against the JSON API, validates the response envelope,\n\t * and returns the typed `data` payload on success.\n\t */\n\tprotected async request<\n\t\tReqSchema extends ZodTypeAny | undefined,\n\t\tResponseDataSchema extends ZodTypeAny,\n\t>(\n\t\tmethod: \"GET\" | \"PUT\" | \"POST\" | \"DELETE\",\n\t\tpath: string,\n\t\topts: {\n\t\t\trequestSchema?: ReqSchema;\n\t\t\tbody?: ReqSchema extends ZodTypeAny ? z.infer<ReqSchema> : unknown;\n\t\t\tresponseDataSchema: ResponseDataSchema;\n\t\t},\n\t): Promise<z.infer<ResponseDataSchema>> {\n\t\tconst bodyPayload = parseRequestBody(opts.requestSchema, opts.body);\n\t\tconst urlString = new URL(this.config.baseUrl + path).toString();\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await this.config.fetch!(urlString, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t...(this.config.apiKey\n\t\t\t\t\t\t? { \"x-api-key\": this.config.apiKey }\n\t\t\t\t\t\t: { Authorization: `Bearer ${this.config.apiToken}` }),\n\t\t\t\t},\n\t\t\t\tbody: bodyPayload === undefined ? undefined : JSON.stringify(bodyPayload),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow createTransportError(path, urlString, error);\n\t\t}\n\n\t\tconst responseBody = await readApiResponseBody(path, urlString, response);\n\n\t\tif (response.ok) {\n\t\t\treturn parseSuccessfulResponse(\n\t\t\t\tpath,\n\t\t\t\turlString,\n\t\t\t\tresponse,\n\t\t\t\tresponseBody,\n\t\t\t\topts.responseDataSchema,\n\t\t\t);\n\t\t}\n\n\t\tthrow createResponseError(path, urlString, response, responseBody);\n\t}\n\n\t/**\n\t * GET convenience method inferring response type from schema.\n\t */\n\tprotected get<ResponseDataSchema extends ZodTypeAny>(\n\t\tpath: string,\n\t\tresponseDataSchema: ResponseDataSchema,\n\t): Promise<z.infer<ResponseDataSchema>> {\n\t\treturn this.request(\"GET\", path, { responseDataSchema });\n\t}\n\n\t/**\n\t * PUT convenience method inferring both request and response types.\n\t */\n\tprotected put<ReqSchema extends ZodTypeAny, ResponseDataSchema extends ZodTypeAny>(\n\t\tpath: string,\n\t\tbody: z.infer<ReqSchema>,\n\t\trequestSchema: ReqSchema,\n\t\tresponseDataSchema: ResponseDataSchema,\n\t): Promise<z.infer<ResponseDataSchema>> {\n\t\treturn this.request(\"PUT\", path, { body, requestSchema, responseDataSchema });\n\t}\n}\n\nfunction trimTrailingSlashes(value: string): string {\n\tlet end = value.length;\n\n\twhile (end > 0 && value.charCodeAt(end - 1) === 47) {\n\t\tend -= 1;\n\t}\n\n\treturn end === value.length ? value : value.slice(0, end);\n}\n","import { z } from \"zod\";\n\n/**\n * -----------------------------------------\n * Legacy API Schemas & Types\n *\n * These schemas map to expected types for Hub Pages rendered by dotcom-pages.\n * -----------------------------------------\n */\n\nconst LegacyFlourishChildSchema = z.object({\n\tsource: z.literal(\"flourish\"),\n\tproperties: z.object({\n\t\tid: z.string().min(1), // e.g. \"visualisation/21901162\"\n\t}),\n});\n\nconst LegacyListChildSchema = z.object({\n\tsource: z.literal(\"list\"),\n\tproperties: z.object({\n\t\tid: z.string().uuid(),\n\t\tmaxItems: z.number().optional(),\n\t}),\n});\n\nconst LegacyContentChildSchema = z.object({\n\tsource: z.literal(\"content\"),\n\tproperties: z.object({\n\t\tids: z.array(z.string()).nonempty(),\n\t}),\n});\n\nconst LegacyContainerChildSchema = z.discriminatedUnion(\"source\", [\n\tLegacyFlourishChildSchema,\n\tLegacyListChildSchema,\n\tLegacyContentChildSchema,\n]);\n\nconst LegacyTopperSchema = z.object({\n\ttype: z.literal(\"topper-basic\"),\n\tproperties: z.object({\n\t\ttitle: z.string(),\n\t\tsponsorText: z.string().optional(),\n\t\tsponsorImage: z.string().url().optional(),\n\t}),\n});\n\nconst LegacyInfoBoxSchema = z.object({\n\ttype: z.literal(\"info-box\"),\n\tproperties: z.object({\n\t\tbodyHTML: z.string(),\n\t\ttitle: z.string().optional(),\n\t}),\n});\n\nconst LegacyContainerSchema = z.object({\n\ttype: z.literal(\"container\"),\n\tchildren: z.array(LegacyContainerChildSchema).min(1),\n\tproperties: z.object({\n\t\ttitle: z.string().optional(),\n\t\tdesign: z.enum([\"chart\", \"four-story\", \"freeform\", \"hero-lead\"]).default(\"freeform\"),\n\t\tbackgroundColor: z.string().optional(),\n\t}),\n});\n\nconst LegacyExperimentSchema = z.object({\n\ttype: z.literal(\"experiment\"),\n\tchildren: z.tuple([]),\n\tproperties: z.object({\n\t\texperimentName: z.string(),\n\t\tid: z.string(),\n\t\ttitle: z.string().optional(),\n\t\tconfig: z\n\t\t\t.object({\n\t\t\t\tvalue: z.unknown().optional(),\n\t\t\t\t// Hub pages support experiments with HTML and Text.\n\t\t\t\t// For now we just support JSON. As we migrate pages, this may change.\n\t\t\t\tformat: z.enum([\"json\"]).default(\"json\"),\n\t\t\t})\n\t\t\t.partial()\n\t\t\t.optional(),\n\t}),\n});\n\nconst LegacyBlockSchema = z.discriminatedUnion(\"type\", [\n\tLegacyTopperSchema,\n\tLegacyInfoBoxSchema,\n\tLegacyContainerSchema,\n\tLegacyExperimentSchema,\n]);\n\nexport const LegacyPageStructureOutputSchema = z.object({\n\tuuid: z.string().uuid(),\n\ttitle: z.string(),\n\tconceptId: z.string().uuid().optional(),\n\tthemeName: z.string().optional(),\n\tmetaDescription: z.string().optional(),\n\tblocks: z.array(LegacyBlockSchema),\n});\n\nexport type LegacyPageStructureOutput = z.infer<typeof LegacyPageStructureOutputSchema>;\nexport type LegacyBlock = z.infer<typeof LegacyBlockSchema>;\n","import { z } from \"zod\";\nimport { ProseMirrorDocSchema } from \"../../prosemirror\";\n\n//\n// 1) REUSABLE SCHEMAS FOR COMMON STRUCTURES\n//\n\n/**\n * A generic schema representing a heading used across various slices.\n * - `text`: The display text of the heading.\n * - `href`: An optional URL that the heading links to.\n */\nconst HeadingSchema = z.object({\n\ttext: z.string(),\n\thref: z.string().url().optional(),\n});\n\n/**\n * Base “properties” common to most page slices.\n * - `heading`: An optional heading object for slices that can display a title.\n */\nconst BasePageItemProps = z.object({\n\theading: HeadingSchema.optional(),\n});\n\n/**\n * A schema to validate that a string is valid JSON.\n */\nconst ValidJSONStringSchema = z.string().refine(\n\t(val) => {\n\t\ttry {\n\t\t\tJSON.parse(val);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n\t{ message: \"Invalid JSON string\" },\n);\n\n//\n// 2) GENERIC HELPER TO DEFINE “SLICE” INPUT/OUTPUT SCHEMAS\n//\n\n/**\n * A union type to represent either a Zod object schema or an optional Zod object schema.\n */\ntype OptionalOrRequiredZodObject = z.AnyZodObject | z.ZodOptional<z.AnyZodObject>;\n\n/**\n * Helper function that, given:\n * - `typeName`: A string literal identifying the slice type.\n * - `propsShape`: A Zod schema describing the slice’s `properties`.\n *\n * Returns an object containing two schemas:\n * - `InputSchema`: For client-side input; `sliceId` is optional.\n * - `OutputSchema`: For server-side/output; `sliceId` is required.\n *\n * This is useful because when defining slices we often want to allow -\n * clients to submit slices without an ID (e.g., when creating new slices),\n */\nfunction defineSliceSchema<T extends string, P extends OptionalOrRequiredZodObject>(options: {\n\ttypeName: T;\n\tpropsShape: P;\n}) {\n\tconst { typeName, propsShape } = options;\n\n\t// Base schema shared by both input and output:\n\t// - `type`: Literal string identifying which slice this is.\n\t// - `hidden`: Optional flag to mark the slice as hidden.\n\t// - `properties`: The detailed properties shape for the slice.\n\tconst BaseSchema = z.object({\n\t\ttype: z.literal(typeName),\n\t\thidden: z.boolean().optional(),\n\t\tproperties: propsShape,\n\t});\n\n\t/**\n\t * Input schema: For client submissions.\n\t * - `sliceId` is optional because the client might not specify it yet.\n\t */\n\tconst InputSchema = BaseSchema.extend({\n\t\tsliceId: z.string().uuid().optional(),\n\t});\n\n\t/**\n\t * Output schema: For persisted or server-returned data.\n\t * - `sliceId` is required (each saved slice must have an ID).\n\t */\n\tconst OutputSchema = BaseSchema.extend({\n\t\tsliceId: z.string().uuid(),\n\t});\n\n\treturn { InputSchema, OutputSchema };\n}\n\n//\n// 3) DEFINE INDIVIDUAL SLICE TYPES (INPUT & OUTPUT) USING THE HELPER\n//\n\n// 3.A “InteractiveSlice”\n// - A slice to embed or reference a Flourish graphic by its ID.\n// - Extends graphic base properties with `flourishId` and `flourishAltText`, with optional 'theme', 'flourishDescription' or 'storyUUID'.\nconst InteractiveSlice = defineSliceSchema({\n\ttypeName: \"Interactive\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tflourishDescription: z.string().optional(), // Optional description for the Flourish graphic\n\t\tflourishId: z.string().nonempty(),\n\t\tflourishAltText: z.string().nonempty(),\n\t\tstoryUUID: z.string().uuid().optional(),\n\t\ttheme: z.string().optional(),\n\t}),\n});\n\n// 3.B “ExperimentSlice”\n// - A slice for embedding experimental content.\n// - Requires an `experimentId`, `experimentName`, and a JSON string (`contentJson`).\nconst ExperimentSlice = defineSliceSchema({\n\ttypeName: \"Experiment\",\n\tpropsShape: BasePageItemProps.extend({\n\t\texperimentId: z.string().nonempty(), // Unique ID for the experiment\n\t\texperimentName: z.string().nonempty(), // Human-readable name of the experiment\n\t\tcontentJson: ValidJSONStringSchema, // The experiment’s JSON payload as a valid JSON string\n\t}),\n});\n\n// 3.C \"Strip\"\n// - A slice that displays a strip of content.\nconst StripSlice = defineSliceSchema({\n\ttypeName: \"Strip\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tlistId: z.string().uuid(), // The ID of the strip to display\n\t\tmaxStories: z.number().int().min(1).max(20), // Maximum number of stories to display in the strip\n\t}),\n});\n\n// 3.D \"TopperSlice\"\n// - A slice that displays a topper section with description and optional strapline.\nconst TopperSlice = defineSliceSchema({\n\ttypeName: \"Topper\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tdescription: ProseMirrorDocSchema,\n\t\tstrapline: z.string().optional(),\n\t}),\n});\n\n// 3.E \"Hero\"\n// - A slice that represents a Hero on the page. It references a Spark List.\nconst HeroSlice = defineSliceSchema({\n\ttypeName: \"Hero\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tlistId: z.string().uuid(), // The ID of the spark list to display\n\t\tmaxStories: z.number().int().min(1).max(20), // Maximum number of stories to display in the hero\n\t}),\n});\n\n// 3.G \"StoryGroup\"\n// - A slice that stores an ordered list of manually curated content ids.\nconst StoryGroupSlice = defineSliceSchema({\n\ttypeName: \"StoryGroup\",\n\tpropsShape: BasePageItemProps.extend({\n\t\tstorySlots: z.array(z.string().uuid()).nonempty(),\n\t}),\n});\n\n//\n// 4) COMPOSE DISCRIMINATED UNIONS FOR “SLICE API” INPUT & OUTPUT\n//\n\n/**\n * All possible slice inputs for the Page API.\n * This discriminated union allows Zod to pick the correct schema based on the `type` field.\n */\nexport const SliceApiInputSchema = z.discriminatedUnion(\"type\", [\n\tInteractiveSlice.InputSchema,\n\tExperimentSlice.InputSchema,\n\tStripSlice.InputSchema,\n\tTopperSlice.InputSchema,\n\tHeroSlice.InputSchema,\n\tStoryGroupSlice.InputSchema,\n] as const);\n\n/**\n * All possible slice outputs for the Page API.\n * The same discriminated union but with each slice requiring `sliceId`.\n */\nexport const SliceApiOutputSchema = z.discriminatedUnion(\"type\", [\n\tInteractiveSlice.OutputSchema,\n\tExperimentSlice.OutputSchema,\n\tStripSlice.OutputSchema,\n\tTopperSlice.OutputSchema,\n\tHeroSlice.OutputSchema,\n\tStoryGroupSlice.OutputSchema,\n] as const);\n\n//\n// 5) WRAPPER SCHEMAS FOR THE ENTIRE PAGE STRUCTURE\n//\n\nconst BasePagePropertiesSchema = z.object({\n\ttitle: z.string(),\n\tpageId: z.string().uuid(),\n\tpublicationId: z.string(),\n\tconceptId: z.string().uuid().optional(),\n\tmetaDescription: z.string().optional(),\n\tpageTheme: z.string().optional(),\n\tsponsorText: z.string().optional(),\n\tsponsorImage: z.string().url().optional(),\n\tpageCategory: z.string().optional(),\n});\n\n/**\n * Page structure as submitted by clients.\n * - `properties`: Metadata about the page\n * - `children`: Array of slice inputs (each with an optional `sliceId`).\n */\nexport const PageStructureInputSchema = z.object({\n\tproperties: BasePagePropertiesSchema,\n\tchildren: z.array(SliceApiInputSchema),\n});\n\n/**\n * Page structure as stored or returned by the server.\n */\nexport const PageStructureOutputSchema = z.object({\n\ttype: z.literal(\"Page\"),\n\tschemaVersion: z.number(),\n\tproperties: BasePagePropertiesSchema,\n\tchildren: z.array(SliceApiOutputSchema),\n});\n\n//\n// 6) EXPORT TYPES FOR CONSUMPTION IN CODE\n//\n\n/** Client-side type for page structure input */\nexport type PageStructureInput = z.infer<typeof PageStructureInputSchema>;\n\n/** Server-side type for page structure output */\nexport type PageStructureOutput = z.infer<typeof PageStructureOutputSchema>;\n\n/** Union of all possible slice outputs for type-checking convenience */\nexport type Slice = z.infer<typeof SliceApiOutputSchema>;\n\n/** Individual slice output types */\nexport type InteractiveSliceType = z.infer<typeof InteractiveSlice.OutputSchema>;\nexport type ExperimentSliceType = z.infer<typeof ExperimentSlice.OutputSchema>;\nexport type StripSliceType = z.infer<typeof StripSlice.OutputSchema>;\nexport type TopperSliceType = z.infer<typeof TopperSlice.OutputSchema>;\nexport type HeroSliceType = z.infer<typeof HeroSlice.OutputSchema>;\nexport type StoryGroupSliceType = z.infer<typeof StoryGroupSlice.OutputSchema>;\n","import { z } from \"zod\";\n\n/** Accept http(s) and mailto: (matches your editor config) */\nconst HrefSchema = z.string().refine((v) => /^(https?:\\/\\/|mailto:).+/.test(v), {\n\tmessage: \"Expected http(s):// or mailto: URL\",\n});\n\n/** Link mark. */\nconst ProseMirrorLinkMark = z.object({\n\ttype: z.literal(\"link\"),\n\tattrs: z.object({\n\t\thref: HrefSchema,\n\t}),\n});\n\n/** Supported text marks */\nconst ProseMirrorMark = z.discriminatedUnion(\"type\", [\n\tProseMirrorLinkMark,\n\tz.object({ type: z.literal(\"bold\") }),\n\tz.object({ type: z.literal(\"italic\") }),\n\tz.object({ type: z.literal(\"underline\") }),\n\tz.object({ type: z.literal(\"strike\") }),\n]);\n\n/** Text node */\nconst ProseMirrorTextNode = z.object({\n\ttype: z.literal(\"text\"),\n\ttext: z.string(),\n\tmarks: z.array(ProseMirrorMark).optional(),\n});\n\n/** Paragraph node — content can be empty/omitted */\nconst ProseMirrorParagraphNode = z.object({\n\ttype: z.literal(\"paragraph\"),\n\tcontent: z.array(ProseMirrorTextNode),\n});\n\n/** ProseMirror Node Union. */\nconst ProseMirrorNode = z.union([ProseMirrorParagraphNode, ProseMirrorTextNode]);\n\n/** Root node of a ProseMirror document - enforcing at least 1 paragraph */\nexport const ProseMirrorDocSchema = z.object({\n\ttype: z.literal(\"doc\"),\n\tcontent: z\n\t\t.array(ProseMirrorNode)\n\t\t.min(1, { message: \"Document must contain at least one paragraph\" }),\n});\n\n/** Rich text editor TS type. */\nexport type RichTextEditorType = z.infer<typeof ProseMirrorDocSchema>;\n\nexport {};\n","import { z } from \"zod\";\nimport { PageStructureInputSchema, PageStructureOutputSchema } from \"../page\";\n\nexport const DraftContributorInputSchema = z.object({\n\tuserId: z.string().min(1),\n\tdisplayName: z.string().min(1),\n\temail: z.string().email().optional(),\n});\n\nexport const DraftContributorSchema = DraftContributorInputSchema.extend({\n\tuserId: z.string().min(1),\n\tdisplayName: z.string().min(1),\n\tfirstTouchedAt: z.string().datetime(),\n\tlastTouchedAt: z.string().datetime(),\n});\n\nconst DraftMetadataSchema = z.object({\n\tdraftId: z.string().uuid(),\n\tcreatedAt: z.string().datetime(),\n\tupdatedAt: z.string().datetime(),\n\tcontributors: z.array(DraftContributorSchema),\n});\n\nexport const PageDraftSchema = DraftMetadataSchema.extend({\n\tstructure: PageStructureOutputSchema,\n});\n\nexport const DraftSchema = PageDraftSchema;\n\nexport const PersistPageDraftInputSchema = z.object({\n\tstructure: PageStructureInputSchema,\n\tcontributor: DraftContributorInputSchema,\n});\n\nexport type DraftContributorInput = z.infer<typeof DraftContributorInputSchema>;\nexport type DraftContributor = z.infer<typeof DraftContributorSchema>;\nexport type PageDraft = z.infer<typeof PageDraftSchema>;\nexport type Draft = z.infer<typeof DraftSchema>;\nexport type PersistPageDraftInput = z.infer<typeof PersistPageDraftInputSchema>;\n","import { BaseApiClient } from \"./base\";\nimport { ApiServiceError } from \"./errors\";\nimport type { LegacyPageStructureOutput } from \"./schemas/ftpink/legacyHubPage\";\nimport { LegacyPageStructureOutputSchema } from \"./schemas/ftpink/legacyHubPage\";\nimport {\n\tPageStructureInputSchema,\n\tPageStructureOutputSchema,\n\ttype PageStructureInput,\n\ttype PageStructureOutput,\n} from \"./schemas/ftpink/page\";\nimport { PageDraftSchema, type PageDraft } from \"./schemas/ftpink/draft\";\n\n/**\n * Client for Page structure endpoints\n */\nexport class PageClient extends BaseApiClient {\n\tasync getStructure(pageId: string): Promise<PageStructureOutput> {\n\t\treturn this.get(`/v1/page/${pageId}/structure`, PageStructureOutputSchema);\n\t}\n\n\tasync getDraft(pageId: string): Promise<PageDraft | null> {\n\t\ttry {\n\t\t\treturn await this.get(`/v1/page/${pageId}/draft`, PageDraftSchema);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiServiceError && error.code === \"NOT_FOUND\") {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync getLegacyHubPageStructure(pageId: string): Promise<LegacyPageStructureOutput> {\n\t\treturn this.get(`/v1/page/${pageId}/legacyHubPageStructure`, LegacyPageStructureOutputSchema);\n\t}\n\n\tasync upsertStructure(\n\t\tpageId: string,\n\t\tdata: Omit<PageStructureInput, \"type\">,\n\t): Promise<PageStructureOutput> {\n\t\treturn this.put(\n\t\t\t`/v1/page/${pageId}/structure`,\n\t\t\tdata,\n\t\t\tPageStructureInputSchema,\n\t\t\tPageStructureOutputSchema,\n\t\t);\n\t}\n}\n","import type { ApiClientConfig } from \"./base\";\nimport { BaseApiClient } from \"./base\";\nimport { PageClient } from \"./page\";\n\n/**\n * Main API client that provides access to all API endpoints\n */\nexport class ApiClient extends BaseApiClient {\n\tpage: PageClient;\n\n\tconstructor(config: ApiClientConfig) {\n\t\tsuper(config);\n\n\t\t// Initialize sub-client\n\t\tthis.page = new PageClient(config);\n\t}\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -8,12 +8,7 @@ export { ApiClientError_alias_1 as ApiClientError } from './_tsup-dts-rollup.cjs
|
|
|
8
8
|
export { ApiGatewayError_alias_1 as ApiGatewayError } from './_tsup-dts-rollup.cjs';
|
|
9
9
|
export { ApiServiceError_alias_1 as ApiServiceError } from './_tsup-dts-rollup.cjs';
|
|
10
10
|
export { ApiTransportError_alias_1 as ApiTransportError } from './_tsup-dts-rollup.cjs';
|
|
11
|
-
export { HomepageClient_alias_1 as HomepageClient } from './_tsup-dts-rollup.cjs';
|
|
12
11
|
export { PageClient } from './_tsup-dts-rollup.cjs';
|
|
13
|
-
export { HomepageStructureInputSchema } from './_tsup-dts-rollup.cjs';
|
|
14
|
-
export { HomepageStructureOutputSchema } from './_tsup-dts-rollup.cjs';
|
|
15
|
-
export { HomepageStructureInput } from './_tsup-dts-rollup.cjs';
|
|
16
|
-
export { HomepageStructureOutput } from './_tsup-dts-rollup.cjs';
|
|
17
12
|
export { PageStructureInputSchema } from './_tsup-dts-rollup.cjs';
|
|
18
13
|
export { PageStructureOutputSchema } from './_tsup-dts-rollup.cjs';
|
|
19
14
|
export { PageStructureInput } from './_tsup-dts-rollup.cjs';
|
|
@@ -21,7 +16,6 @@ export { PageStructureOutput } from './_tsup-dts-rollup.cjs';
|
|
|
21
16
|
export { Slice } from './_tsup-dts-rollup.cjs';
|
|
22
17
|
export { InteractiveSliceType } from './_tsup-dts-rollup.cjs';
|
|
23
18
|
export { ExperimentSliceType } from './_tsup-dts-rollup.cjs';
|
|
24
|
-
export { HomepageSliceType } from './_tsup-dts-rollup.cjs';
|
|
25
19
|
export { StripSliceType } from './_tsup-dts-rollup.cjs';
|
|
26
20
|
export { TopperSliceType } from './_tsup-dts-rollup.cjs';
|
|
27
21
|
export { HeroSliceType } from './_tsup-dts-rollup.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -8,12 +8,7 @@ export { ApiClientError_alias_1 as ApiClientError } from './_tsup-dts-rollup.js'
|
|
|
8
8
|
export { ApiGatewayError_alias_1 as ApiGatewayError } from './_tsup-dts-rollup.js';
|
|
9
9
|
export { ApiServiceError_alias_1 as ApiServiceError } from './_tsup-dts-rollup.js';
|
|
10
10
|
export { ApiTransportError_alias_1 as ApiTransportError } from './_tsup-dts-rollup.js';
|
|
11
|
-
export { HomepageClient_alias_1 as HomepageClient } from './_tsup-dts-rollup.js';
|
|
12
11
|
export { PageClient } from './_tsup-dts-rollup.js';
|
|
13
|
-
export { HomepageStructureInputSchema } from './_tsup-dts-rollup.js';
|
|
14
|
-
export { HomepageStructureOutputSchema } from './_tsup-dts-rollup.js';
|
|
15
|
-
export { HomepageStructureInput } from './_tsup-dts-rollup.js';
|
|
16
|
-
export { HomepageStructureOutput } from './_tsup-dts-rollup.js';
|
|
17
12
|
export { PageStructureInputSchema } from './_tsup-dts-rollup.js';
|
|
18
13
|
export { PageStructureOutputSchema } from './_tsup-dts-rollup.js';
|
|
19
14
|
export { PageStructureInput } from './_tsup-dts-rollup.js';
|
|
@@ -21,7 +16,6 @@ export { PageStructureOutput } from './_tsup-dts-rollup.js';
|
|
|
21
16
|
export { Slice } from './_tsup-dts-rollup.js';
|
|
22
17
|
export { InteractiveSliceType } from './_tsup-dts-rollup.js';
|
|
23
18
|
export { ExperimentSliceType } from './_tsup-dts-rollup.js';
|
|
24
|
-
export { HomepageSliceType } from './_tsup-dts-rollup.js';
|
|
25
19
|
export { StripSliceType } from './_tsup-dts-rollup.js';
|
|
26
20
|
export { TopperSliceType } from './_tsup-dts-rollup.js';
|
|
27
21
|
export { HeroSliceType } from './_tsup-dts-rollup.js';
|