@timbenniks/contentstack-platform-sdk 0.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/dist/auth/index.cjs +607 -0
- package/dist/auth/index.cjs.map +1 -0
- package/dist/auth/index.d.cts +108 -0
- package/dist/auth/index.d.ts +108 -0
- package/dist/auth/index.mjs +25 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/brandkit/index.cjs +525 -0
- package/dist/brandkit/index.cjs.map +1 -0
- package/dist/brandkit/index.d.cts +95 -0
- package/dist/brandkit/index.d.ts +95 -0
- package/dist/brandkit/index.mjs +11 -0
- package/dist/brandkit/index.mjs.map +1 -0
- package/dist/chunk-3C6J2BDB.mjs +84 -0
- package/dist/chunk-3C6J2BDB.mjs.map +1 -0
- package/dist/chunk-3KE63N3I.mjs +64 -0
- package/dist/chunk-3KE63N3I.mjs.map +1 -0
- package/dist/chunk-4CJ4IVPJ.mjs +212 -0
- package/dist/chunk-4CJ4IVPJ.mjs.map +1 -0
- package/dist/chunk-4JFUI7MJ.mjs +368 -0
- package/dist/chunk-4JFUI7MJ.mjs.map +1 -0
- package/dist/chunk-7VFGD32I.mjs +26 -0
- package/dist/chunk-7VFGD32I.mjs.map +1 -0
- package/dist/chunk-ARPJDW3A.mjs +44 -0
- package/dist/chunk-ARPJDW3A.mjs.map +1 -0
- package/dist/chunk-AVJHCFRK.mjs +52 -0
- package/dist/chunk-AVJHCFRK.mjs.map +1 -0
- package/dist/chunk-BK2IBTQS.mjs +131 -0
- package/dist/chunk-BK2IBTQS.mjs.map +1 -0
- package/dist/chunk-BUZ6CQHE.mjs +75 -0
- package/dist/chunk-BUZ6CQHE.mjs.map +1 -0
- package/dist/chunk-CKMAOWBQ.mjs +379 -0
- package/dist/chunk-CKMAOWBQ.mjs.map +1 -0
- package/dist/chunk-DJQLN4TR.mjs +1 -0
- package/dist/chunk-DJQLN4TR.mjs.map +1 -0
- package/dist/chunk-DMERADWM.mjs +67 -0
- package/dist/chunk-DMERADWM.mjs.map +1 -0
- package/dist/chunk-EREPKWTW.mjs +926 -0
- package/dist/chunk-EREPKWTW.mjs.map +1 -0
- package/dist/chunk-FQP4PB5X.mjs +88 -0
- package/dist/chunk-FQP4PB5X.mjs.map +1 -0
- package/dist/chunk-GNPQJBFX.mjs +144 -0
- package/dist/chunk-GNPQJBFX.mjs.map +1 -0
- package/dist/chunk-GOSB24M6.mjs +87 -0
- package/dist/chunk-GOSB24M6.mjs.map +1 -0
- package/dist/chunk-JL2E3EOT.mjs +255 -0
- package/dist/chunk-JL2E3EOT.mjs.map +1 -0
- package/dist/chunk-JYGZBKTH.mjs +222 -0
- package/dist/chunk-JYGZBKTH.mjs.map +1 -0
- package/dist/chunk-JZE2W7VW.mjs +52 -0
- package/dist/chunk-JZE2W7VW.mjs.map +1 -0
- package/dist/chunk-K76DKSHJ.mjs +18 -0
- package/dist/chunk-K76DKSHJ.mjs.map +1 -0
- package/dist/chunk-KLVIROVU.mjs +232 -0
- package/dist/chunk-KLVIROVU.mjs.map +1 -0
- package/dist/chunk-LPVVA5J3.mjs +18 -0
- package/dist/chunk-LPVVA5J3.mjs.map +1 -0
- package/dist/chunk-NKLOZ5VI.mjs +112 -0
- package/dist/chunk-NKLOZ5VI.mjs.map +1 -0
- package/dist/chunk-QGA4WBDC.mjs +7 -0
- package/dist/chunk-QGA4WBDC.mjs.map +1 -0
- package/dist/chunk-QW7TVYOA.mjs +56 -0
- package/dist/chunk-QW7TVYOA.mjs.map +1 -0
- package/dist/chunk-SU5QEKYW.mjs +83 -0
- package/dist/chunk-SU5QEKYW.mjs.map +1 -0
- package/dist/chunk-T5A2E2RI.mjs +654 -0
- package/dist/chunk-T5A2E2RI.mjs.map +1 -0
- package/dist/chunk-T5OIJQK7.mjs +116 -0
- package/dist/chunk-T5OIJQK7.mjs.map +1 -0
- package/dist/chunk-VW7DD6HV.mjs +253 -0
- package/dist/chunk-VW7DD6HV.mjs.map +1 -0
- package/dist/chunk-XH7NLHGW.mjs +133 -0
- package/dist/chunk-XH7NLHGW.mjs.map +1 -0
- package/dist/client-DJ5haQGd.d.cts +22 -0
- package/dist/client-DwVGVSQz.d.ts +22 -0
- package/dist/cma/index.cjs +1349 -0
- package/dist/cma/index.cjs.map +1 -0
- package/dist/cma/index.d.cts +22 -0
- package/dist/cma/index.d.ts +22 -0
- package/dist/cma/index.mjs +70 -0
- package/dist/cma/index.mjs.map +1 -0
- package/dist/errors-CAw-IRCP.d.cts +65 -0
- package/dist/errors-CAw-IRCP.d.ts +65 -0
- package/dist/generative-ai/index.cjs +401 -0
- package/dist/generative-ai/index.cjs.map +1 -0
- package/dist/generative-ai/index.d.cts +31 -0
- package/dist/generative-ai/index.d.ts +31 -0
- package/dist/generative-ai/index.mjs +10 -0
- package/dist/generative-ai/index.mjs.map +1 -0
- package/dist/images/index.cjs +185 -0
- package/dist/images/index.cjs.map +1 -0
- package/dist/images/index.d.cts +27 -0
- package/dist/images/index.d.ts +27 -0
- package/dist/images/index.mjs +8 -0
- package/dist/images/index.mjs.map +1 -0
- package/dist/index.cjs +2909 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.mjs +153 -0
- package/dist/index.mjs.map +1 -0
- package/dist/knowledge-vault/index.cjs +413 -0
- package/dist/knowledge-vault/index.cjs.map +1 -0
- package/dist/knowledge-vault/index.d.cts +49 -0
- package/dist/knowledge-vault/index.d.ts +49 -0
- package/dist/knowledge-vault/index.mjs +10 -0
- package/dist/knowledge-vault/index.mjs.map +1 -0
- package/dist/launch/index.cjs +624 -0
- package/dist/launch/index.cjs.map +1 -0
- package/dist/launch/index.d.cts +169 -0
- package/dist/launch/index.d.ts +169 -0
- package/dist/launch/index.mjs +11 -0
- package/dist/launch/index.mjs.map +1 -0
- package/dist/react/auth/index.cjs +113 -0
- package/dist/react/auth/index.cjs.map +1 -0
- package/dist/react/auth/index.d.cts +33 -0
- package/dist/react/auth/index.d.ts +33 -0
- package/dist/react/auth/index.mjs +13 -0
- package/dist/react/auth/index.mjs.map +1 -0
- package/dist/react/content/index.cjs +113 -0
- package/dist/react/content/index.cjs.map +1 -0
- package/dist/react/content/index.d.cts +25 -0
- package/dist/react/content/index.d.ts +25 -0
- package/dist/react/content/index.mjs +7 -0
- package/dist/react/content/index.mjs.map +1 -0
- package/dist/react/hooks/index.cjs +2097 -0
- package/dist/react/hooks/index.cjs.map +1 -0
- package/dist/react/hooks/index.d.cts +77 -0
- package/dist/react/hooks/index.d.ts +77 -0
- package/dist/react/hooks/index.mjs +46 -0
- package/dist/react/hooks/index.mjs.map +1 -0
- package/dist/react/index.cjs +2307 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +16 -0
- package/dist/react/index.d.ts +16 -0
- package/dist/react/index.mjs +67 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/react/provider/index.cjs +83 -0
- package/dist/react/provider/index.cjs.map +1 -0
- package/dist/react/provider/index.d.cts +30 -0
- package/dist/react/provider/index.d.ts +30 -0
- package/dist/react/provider/index.mjs +11 -0
- package/dist/react/provider/index.mjs.map +1 -0
- package/dist/regions/index.cjs +171 -0
- package/dist/regions/index.cjs.map +1 -0
- package/dist/regions/index.d.cts +55 -0
- package/dist/regions/index.d.ts +55 -0
- package/dist/regions/index.mjs +13 -0
- package/dist/regions/index.mjs.map +1 -0
- package/dist/request-builders-BxeolQIw.d.ts +735 -0
- package/dist/request-builders-C2IG1LUo.d.cts +735 -0
- package/dist/rte/index.cjs +683 -0
- package/dist/rte/index.cjs.map +1 -0
- package/dist/rte/index.d.cts +33 -0
- package/dist/rte/index.d.ts +33 -0
- package/dist/rte/index.mjs +17 -0
- package/dist/rte/index.mjs.map +1 -0
- package/dist/server/index.cjs +917 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.cts +6 -0
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.mjs +45 -0
- package/dist/server/index.mjs.map +1 -0
- package/dist/server/middleware/index.cjs +614 -0
- package/dist/server/middleware/index.cjs.map +1 -0
- package/dist/server/middleware/index.d.cts +77 -0
- package/dist/server/middleware/index.d.ts +77 -0
- package/dist/server/middleware/index.mjs +27 -0
- package/dist/server/middleware/index.mjs.map +1 -0
- package/dist/server/proxy/index.cjs +329 -0
- package/dist/server/proxy/index.cjs.map +1 -0
- package/dist/server/proxy/index.d.cts +143 -0
- package/dist/server/proxy/index.d.ts +143 -0
- package/dist/server/proxy/index.mjs +29 -0
- package/dist/server/proxy/index.mjs.map +1 -0
- package/dist/server/webhooks/index.cjs +131 -0
- package/dist/server/webhooks/index.cjs.map +1 -0
- package/dist/server/webhooks/index.d.cts +230 -0
- package/dist/server/webhooks/index.d.ts +230 -0
- package/dist/server/webhooks/index.mjs +23 -0
- package/dist/server/webhooks/index.mjs.map +1 -0
- package/dist/types-6D9VR7pT.d.cts +26 -0
- package/dist/types-AelT0rFJ.d.cts +21 -0
- package/dist/types-AelT0rFJ.d.ts +21 -0
- package/dist/types-Bu5yCgmw.d.ts +26 -0
- package/dist/types-DgixK-ll.d.cts +23 -0
- package/dist/types-DgixK-ll.d.ts +23 -0
- package/dist/types-DrMwdlH9.d.cts +245 -0
- package/dist/types-DrMwdlH9.d.ts +245 -0
- package/dist/ui/css/index.cjs +31 -0
- package/dist/ui/css/index.cjs.map +1 -0
- package/dist/ui/css/index.d.cts +15 -0
- package/dist/ui/css/index.d.ts +15 -0
- package/dist/ui/css/index.mjs +7 -0
- package/dist/ui/css/index.mjs.map +1 -0
- package/dist/ui/index.cjs +368 -0
- package/dist/ui/index.cjs.map +1 -0
- package/dist/ui/index.d.cts +4 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.mjs +33 -0
- package/dist/ui/index.mjs.map +1 -0
- package/dist/ui/theme/index.cjs +105 -0
- package/dist/ui/theme/index.cjs.map +1 -0
- package/dist/ui/theme/index.d.cts +33 -0
- package/dist/ui/theme/index.d.ts +33 -0
- package/dist/ui/theme/index.mjs +15 -0
- package/dist/ui/theme/index.mjs.map +1 -0
- package/dist/ui/tokens/index.cjs +286 -0
- package/dist/ui/tokens/index.cjs.map +1 -0
- package/dist/ui/tokens/index.d.cts +54 -0
- package/dist/ui/tokens/index.d.ts +54 -0
- package/dist/ui/tokens/index.mjs +17 -0
- package/dist/ui/tokens/index.mjs.map +1 -0
- package/dist/ui/tokens.css +408 -0
- package/dist/vue/auth/index.cjs +141 -0
- package/dist/vue/auth/index.cjs.map +1 -0
- package/dist/vue/auth/index.d.cts +78 -0
- package/dist/vue/auth/index.d.ts +78 -0
- package/dist/vue/auth/index.mjs +13 -0
- package/dist/vue/auth/index.mjs.map +1 -0
- package/dist/vue/composables/index.cjs +2108 -0
- package/dist/vue/composables/index.cjs.map +1 -0
- package/dist/vue/composables/index.d.cts +78 -0
- package/dist/vue/composables/index.d.ts +78 -0
- package/dist/vue/composables/index.mjs +46 -0
- package/dist/vue/composables/index.mjs.map +1 -0
- package/dist/vue/content/index.cjs +142 -0
- package/dist/vue/content/index.cjs.map +1 -0
- package/dist/vue/content/index.d.cts +47 -0
- package/dist/vue/content/index.d.ts +47 -0
- package/dist/vue/content/index.mjs +7 -0
- package/dist/vue/content/index.mjs.map +1 -0
- package/dist/vue/index.cjs +2389 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.cts +16 -0
- package/dist/vue/index.d.ts +16 -0
- package/dist/vue/index.mjs +69 -0
- package/dist/vue/index.mjs.map +1 -0
- package/dist/vue/provider/index.cjs +97 -0
- package/dist/vue/provider/index.cjs.map +1 -0
- package/dist/vue/provider/index.d.cts +90 -0
- package/dist/vue/provider/index.d.ts +90 -0
- package/dist/vue/provider/index.mjs +13 -0
- package/dist/vue/provider/index.mjs.map +1 -0
- package/package.json +195 -0
|
@@ -0,0 +1,917 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/server/index.ts
|
|
31
|
+
var server_exports = {};
|
|
32
|
+
__export(server_exports, {
|
|
33
|
+
checkScope: () => checkScope,
|
|
34
|
+
createBrandKitProxy: () => createBrandKitProxy,
|
|
35
|
+
createCMAProxy: () => createCMAProxy,
|
|
36
|
+
createContentstackAuth: () => createContentstackAuth,
|
|
37
|
+
createLaunchProxy: () => createLaunchProxy,
|
|
38
|
+
createWebhookHandler: () => createWebhookHandler,
|
|
39
|
+
getAccessToken: () => getAccessToken,
|
|
40
|
+
getSession: () => getSession,
|
|
41
|
+
requireSession: () => requireSession,
|
|
42
|
+
resolveScope: () => resolveScope,
|
|
43
|
+
verifyWebhookSignature: () => verifyWebhookSignature
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(server_exports);
|
|
46
|
+
|
|
47
|
+
// src/http/errors.ts
|
|
48
|
+
var ContentstackError = class extends Error {
|
|
49
|
+
name = "ContentstackError";
|
|
50
|
+
status;
|
|
51
|
+
errorCode;
|
|
52
|
+
errors;
|
|
53
|
+
requestPath;
|
|
54
|
+
constructor(message, options) {
|
|
55
|
+
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
56
|
+
this.status = options?.status;
|
|
57
|
+
this.errorCode = options?.errorCode;
|
|
58
|
+
this.errors = options?.errors;
|
|
59
|
+
this.requestPath = options?.requestPath;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var ContentstackAuthError = class extends ContentstackError {
|
|
63
|
+
name = "ContentstackAuthError";
|
|
64
|
+
status = 401;
|
|
65
|
+
};
|
|
66
|
+
var ContentstackForbiddenError = class extends ContentstackError {
|
|
67
|
+
name = "ContentstackForbiddenError";
|
|
68
|
+
status = 403;
|
|
69
|
+
};
|
|
70
|
+
var ContentstackNotFoundError = class extends ContentstackError {
|
|
71
|
+
name = "ContentstackNotFoundError";
|
|
72
|
+
status = 404;
|
|
73
|
+
};
|
|
74
|
+
var ContentstackValidationError = class extends ContentstackError {
|
|
75
|
+
name = "ContentstackValidationError";
|
|
76
|
+
status;
|
|
77
|
+
constructor(message, options) {
|
|
78
|
+
super(message, options);
|
|
79
|
+
this.status = options?.status ?? 400;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var ContentstackInvalidApiKeyError = class extends ContentstackError {
|
|
83
|
+
name = "ContentstackInvalidApiKeyError";
|
|
84
|
+
status = 412;
|
|
85
|
+
};
|
|
86
|
+
var ContentstackRateLimitError = class extends ContentstackError {
|
|
87
|
+
name = "ContentstackRateLimitError";
|
|
88
|
+
status = 429;
|
|
89
|
+
retryAfter;
|
|
90
|
+
constructor(message, options) {
|
|
91
|
+
super(message, { ...options, status: 429 });
|
|
92
|
+
this.retryAfter = options?.retryAfter;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var ContentstackServerError = class extends ContentstackError {
|
|
96
|
+
name = "ContentstackServerError";
|
|
97
|
+
};
|
|
98
|
+
var ContentstackConfigError = class extends ContentstackError {
|
|
99
|
+
name = "ContentstackConfigError";
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/regions/endpoints.ts
|
|
103
|
+
var import_contentstack_endpoints = require("@timbenniks/contentstack-endpoints");
|
|
104
|
+
var BRAND_KIT_URLS = {
|
|
105
|
+
us: {
|
|
106
|
+
brandKit: "https://brand-kits-api.contentstack.com",
|
|
107
|
+
brandKitAI: "https://ai.contentstack.com/brand-kits"
|
|
108
|
+
},
|
|
109
|
+
eu: {
|
|
110
|
+
brandKit: "https://eu-brand-kits-api.contentstack.com",
|
|
111
|
+
brandKitAI: "https://eu-ai.contentstack.com/brand-kits"
|
|
112
|
+
},
|
|
113
|
+
au: {
|
|
114
|
+
brandKit: "https://au-brand-kits-api.contentstack.com",
|
|
115
|
+
brandKitAI: "https://au-ai.contentstack.com/brand-kits"
|
|
116
|
+
},
|
|
117
|
+
"azure-na": {
|
|
118
|
+
brandKit: "https://azure-na-brand-kits-api.contentstack.com",
|
|
119
|
+
brandKitAI: "https://azure-na-ai.contentstack.com/brand-kits"
|
|
120
|
+
},
|
|
121
|
+
"azure-eu": {
|
|
122
|
+
brandKit: "https://azure-eu-brand-kits-api.contentstack.com",
|
|
123
|
+
brandKitAI: "https://azure-eu-ai.contentstack.com/brand-kits"
|
|
124
|
+
},
|
|
125
|
+
"gcp-na": {
|
|
126
|
+
brandKit: "https://gcp-na-brand-kits-api.contentstack.com",
|
|
127
|
+
brandKitAI: "https://gcp-na-ai.contentstack.com/brand-kits"
|
|
128
|
+
},
|
|
129
|
+
"gcp-eu": {
|
|
130
|
+
brandKit: "https://gcp-eu-brand-kits-api.contentstack.com",
|
|
131
|
+
brandKitAI: "https://gcp-eu-ai.contentstack.com/brand-kits"
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
function mapEndpoints(upstream, region, hostsOnly) {
|
|
135
|
+
const bk = BRAND_KIT_URLS[region];
|
|
136
|
+
const stripProtocol = (url) => url.replace(/^https?:\/\//, "");
|
|
137
|
+
return Object.freeze({
|
|
138
|
+
cma: upstream.contentManagement ?? "",
|
|
139
|
+
cda: upstream.contentDelivery ?? "",
|
|
140
|
+
graphql: upstream.graphqlDelivery ?? "",
|
|
141
|
+
images: upstream.images ?? "",
|
|
142
|
+
app: upstream.application ?? "",
|
|
143
|
+
preview: upstream.preview ?? "",
|
|
144
|
+
graphqlPreview: upstream.graphqlPreview ?? "",
|
|
145
|
+
launch: upstream.launch ?? "",
|
|
146
|
+
personalizeEdge: upstream.personalizeEdge ?? "",
|
|
147
|
+
brandKit: hostsOnly ? stripProtocol(bk.brandKit) : bk.brandKit,
|
|
148
|
+
brandKitAI: hostsOnly ? stripProtocol(bk.brandKitAI) : bk.brandKitAI
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
var ALL_REGIONS = [
|
|
152
|
+
"us",
|
|
153
|
+
"eu",
|
|
154
|
+
"au",
|
|
155
|
+
"azure-na",
|
|
156
|
+
"azure-eu",
|
|
157
|
+
"gcp-na",
|
|
158
|
+
"gcp-eu"
|
|
159
|
+
];
|
|
160
|
+
function buildEndpointMap() {
|
|
161
|
+
const map = {};
|
|
162
|
+
for (const region of ALL_REGIONS) {
|
|
163
|
+
map[region] = mapEndpoints((0, import_contentstack_endpoints.getContentstackEndpoints)(region), region, false);
|
|
164
|
+
}
|
|
165
|
+
return Object.freeze(map);
|
|
166
|
+
}
|
|
167
|
+
function buildHostMap() {
|
|
168
|
+
const map = {};
|
|
169
|
+
for (const region of ALL_REGIONS) {
|
|
170
|
+
map[region] = mapEndpoints((0, import_contentstack_endpoints.getContentstackEndpoints)(region, true), region, true);
|
|
171
|
+
}
|
|
172
|
+
return Object.freeze(map);
|
|
173
|
+
}
|
|
174
|
+
var ENDPOINT_MAP = buildEndpointMap();
|
|
175
|
+
var HOST_MAP = buildHostMap();
|
|
176
|
+
|
|
177
|
+
// src/regions/resolver.ts
|
|
178
|
+
var VALID_REGIONS = new Set(Object.keys(ENDPOINT_MAP));
|
|
179
|
+
function resolveEndpoints(region) {
|
|
180
|
+
return ENDPOINT_MAP[region];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/http/client.ts
|
|
184
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
185
|
+
var DEFAULT_RETRY_LIMIT = 5;
|
|
186
|
+
var DEFAULT_RETRY_DELAY = 300;
|
|
187
|
+
var MAX_JITTER = 100;
|
|
188
|
+
var ContentstackHttpClient = class _ContentstackHttpClient {
|
|
189
|
+
config;
|
|
190
|
+
constructor(config) {
|
|
191
|
+
this.config = {
|
|
192
|
+
baseUrl: config.baseUrl,
|
|
193
|
+
headers: config.headers ?? {},
|
|
194
|
+
timeout: config.timeout ?? DEFAULT_TIMEOUT,
|
|
195
|
+
retryOnError: config.retryOnError ?? true,
|
|
196
|
+
retryLimit: config.retryLimit ?? DEFAULT_RETRY_LIMIT,
|
|
197
|
+
retryDelay: config.retryDelay ?? DEFAULT_RETRY_DELAY,
|
|
198
|
+
fetch: config.fetch ?? globalThis.fetch.bind(globalThis)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
async get(path, params) {
|
|
202
|
+
let url = `${this.config.baseUrl}${path}`;
|
|
203
|
+
if (params) {
|
|
204
|
+
const searchParams = new URLSearchParams(params);
|
|
205
|
+
url += `?${searchParams.toString()}`;
|
|
206
|
+
}
|
|
207
|
+
return this.request(url, { method: "GET" }, path);
|
|
208
|
+
}
|
|
209
|
+
async post(path, body) {
|
|
210
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
211
|
+
return this.request(
|
|
212
|
+
url,
|
|
213
|
+
{
|
|
214
|
+
method: "POST",
|
|
215
|
+
headers: { "Content-Type": "application/json" },
|
|
216
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
217
|
+
},
|
|
218
|
+
path
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
async put(path, body) {
|
|
222
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
223
|
+
return this.request(
|
|
224
|
+
url,
|
|
225
|
+
{
|
|
226
|
+
method: "PUT",
|
|
227
|
+
headers: { "Content-Type": "application/json" },
|
|
228
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
229
|
+
},
|
|
230
|
+
path
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
async patch(path, body) {
|
|
234
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
235
|
+
return this.request(
|
|
236
|
+
url,
|
|
237
|
+
{
|
|
238
|
+
method: "PATCH",
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
241
|
+
},
|
|
242
|
+
path
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
async delete(path) {
|
|
246
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
247
|
+
return this.request(url, { method: "DELETE" }, path);
|
|
248
|
+
}
|
|
249
|
+
async postForm(path, params) {
|
|
250
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
251
|
+
return this.request(
|
|
252
|
+
url,
|
|
253
|
+
{
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
256
|
+
body: params.toString()
|
|
257
|
+
},
|
|
258
|
+
path
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
async upload(path, form) {
|
|
262
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
263
|
+
return this.request(url, { method: "POST", body: form }, path);
|
|
264
|
+
}
|
|
265
|
+
/** Return a new client with additional headers merged */
|
|
266
|
+
withHeaders(headers) {
|
|
267
|
+
return new _ContentstackHttpClient({
|
|
268
|
+
...this.config,
|
|
269
|
+
headers: { ...this.config.headers, ...headers }
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/** Return a new client with a different base URL */
|
|
273
|
+
withBaseUrl(baseUrl) {
|
|
274
|
+
return new _ContentstackHttpClient({
|
|
275
|
+
...this.config,
|
|
276
|
+
baseUrl
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
async request(url, init, path) {
|
|
280
|
+
const headers = new Headers(this.config.headers);
|
|
281
|
+
if (init.headers) {
|
|
282
|
+
const initHeaders = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
|
|
283
|
+
initHeaders.forEach((value, key) => headers.set(key, value));
|
|
284
|
+
}
|
|
285
|
+
let lastError;
|
|
286
|
+
const maxAttempts = this.config.retryOnError ? this.config.retryLimit + 1 : 1;
|
|
287
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
288
|
+
const controller = new AbortController();
|
|
289
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
290
|
+
try {
|
|
291
|
+
const response = await this.config.fetch(url, {
|
|
292
|
+
...init,
|
|
293
|
+
headers,
|
|
294
|
+
signal: controller.signal
|
|
295
|
+
});
|
|
296
|
+
if (response.ok) {
|
|
297
|
+
const data = await response.json().catch(() => ({}));
|
|
298
|
+
return { data, status: response.status, headers: response.headers };
|
|
299
|
+
}
|
|
300
|
+
const isRetryable = response.status === 429 || response.status >= 500;
|
|
301
|
+
if (isRetryable && this.config.retryOnError && attempt < maxAttempts - 1) {
|
|
302
|
+
const delay = this.calculateDelay(response, attempt);
|
|
303
|
+
await sleep(delay);
|
|
304
|
+
lastError = await this.createError(response, path);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
throw await this.createError(response, path);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (error instanceof ContentstackError) {
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
313
|
+
throw new ContentstackError(`Request timed out after ${this.config.timeout}ms`, {
|
|
314
|
+
requestPath: path,
|
|
315
|
+
cause: error
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
throw new ContentstackError("Network request failed", {
|
|
319
|
+
requestPath: path,
|
|
320
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
321
|
+
});
|
|
322
|
+
} finally {
|
|
323
|
+
clearTimeout(timeoutId);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
throw lastError ?? new ContentstackError("Request failed after retries", { requestPath: path });
|
|
327
|
+
}
|
|
328
|
+
calculateDelay(response, attempt) {
|
|
329
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
330
|
+
if (retryAfter) {
|
|
331
|
+
const seconds = Number.parseFloat(retryAfter);
|
|
332
|
+
if (!Number.isNaN(seconds)) {
|
|
333
|
+
return seconds * 1e3;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const jitter = Math.random() * MAX_JITTER;
|
|
337
|
+
return this.config.retryDelay * 2 ** attempt + jitter;
|
|
338
|
+
}
|
|
339
|
+
async createError(response, path) {
|
|
340
|
+
let body = {};
|
|
341
|
+
try {
|
|
342
|
+
body = await response.json();
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
const message = body.error_message ?? body.error_description ?? body.message ?? `HTTP ${response.status} error`;
|
|
346
|
+
const errorCode = body.error_code;
|
|
347
|
+
const errors = body.errors;
|
|
348
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
349
|
+
const opts = { status: response.status, errorCode, errors, requestPath: path };
|
|
350
|
+
switch (response.status) {
|
|
351
|
+
case 400:
|
|
352
|
+
return new ContentstackValidationError(message, { ...opts, status: 400 });
|
|
353
|
+
case 401:
|
|
354
|
+
return new ContentstackAuthError(message, opts);
|
|
355
|
+
case 403:
|
|
356
|
+
return new ContentstackForbiddenError(message, opts);
|
|
357
|
+
case 404:
|
|
358
|
+
return new ContentstackNotFoundError(message, opts);
|
|
359
|
+
case 412:
|
|
360
|
+
return new ContentstackInvalidApiKeyError(message, opts);
|
|
361
|
+
case 422:
|
|
362
|
+
return new ContentstackValidationError(message, { ...opts, status: 422 });
|
|
363
|
+
case 429:
|
|
364
|
+
return new ContentstackRateLimitError(message, {
|
|
365
|
+
...opts,
|
|
366
|
+
retryAfter: retryAfter ? Number.parseFloat(retryAfter) : void 0
|
|
367
|
+
});
|
|
368
|
+
default:
|
|
369
|
+
if (response.status >= 500) {
|
|
370
|
+
return new ContentstackServerError(message, opts);
|
|
371
|
+
}
|
|
372
|
+
return new ContentstackError(message, opts);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
function sleep(ms) {
|
|
377
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/auth/oauth-client.ts
|
|
381
|
+
function validateConfig(config) {
|
|
382
|
+
if (!config.appId) {
|
|
383
|
+
throw new ContentstackConfigError(
|
|
384
|
+
"appId is required for OAuth. This is your Contentstack app's UID, not the client ID."
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (config.appId === config.clientId) {
|
|
388
|
+
throw new ContentstackConfigError(
|
|
389
|
+
"appId and clientId must be different. appId is your Contentstack app UID; clientId is the OAuth client identifier."
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function mapTokenResponse(data) {
|
|
394
|
+
return {
|
|
395
|
+
accessToken: data.access_token,
|
|
396
|
+
refreshToken: data.refresh_token,
|
|
397
|
+
expiresIn: data.expires_in,
|
|
398
|
+
tokenType: data.token_type
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async function makeTokenRequest(appBaseUrl, body, errorMessage) {
|
|
402
|
+
const client = new ContentstackHttpClient({ baseUrl: appBaseUrl });
|
|
403
|
+
try {
|
|
404
|
+
const { data } = await client.postForm("/apps-api/token", body);
|
|
405
|
+
return mapTokenResponse(data);
|
|
406
|
+
} catch (err) {
|
|
407
|
+
if (err instanceof ContentstackError) {
|
|
408
|
+
throw new ContentstackAuthError(err.message || errorMessage, {
|
|
409
|
+
status: err.status,
|
|
410
|
+
requestPath: "/apps-api/token",
|
|
411
|
+
cause: err
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
throw new ContentstackAuthError(errorMessage, {
|
|
415
|
+
requestPath: "/apps-api/token",
|
|
416
|
+
cause: err instanceof Error ? err : void 0
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
async function refreshToken(config, token) {
|
|
421
|
+
const endpoints = resolveEndpoints(config.region);
|
|
422
|
+
const body = new URLSearchParams({
|
|
423
|
+
grant_type: "refresh_token",
|
|
424
|
+
refresh_token: token,
|
|
425
|
+
client_id: config.clientId,
|
|
426
|
+
client_secret: config.clientSecret
|
|
427
|
+
});
|
|
428
|
+
return makeTokenRequest(endpoints.app, body, "Failed to refresh token");
|
|
429
|
+
}
|
|
430
|
+
function mapUser(user) {
|
|
431
|
+
return {
|
|
432
|
+
uid: user.uid,
|
|
433
|
+
email: user.email,
|
|
434
|
+
firstName: user.first_name ?? void 0,
|
|
435
|
+
lastName: user.last_name ?? void 0,
|
|
436
|
+
username: user.username ?? void 0,
|
|
437
|
+
profileImage: user.profile_image ?? void 0
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
async function getUser(region, accessToken) {
|
|
441
|
+
const endpoints = resolveEndpoints(region);
|
|
442
|
+
const client = new ContentstackHttpClient({
|
|
443
|
+
baseUrl: `${endpoints.cma}/v3`,
|
|
444
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
445
|
+
});
|
|
446
|
+
try {
|
|
447
|
+
const { data } = await client.get("/user");
|
|
448
|
+
return mapUser(data.user);
|
|
449
|
+
} catch (err) {
|
|
450
|
+
if (err instanceof ContentstackError) {
|
|
451
|
+
throw new ContentstackAuthError(err.message || "Failed to fetch user profile", {
|
|
452
|
+
status: err.status,
|
|
453
|
+
requestPath: "/v3/user",
|
|
454
|
+
cause: err
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
throw new ContentstackAuthError("Failed to fetch user profile", {
|
|
458
|
+
requestPath: "/v3/user",
|
|
459
|
+
cause: err instanceof Error ? err : void 0
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function createAuthProvider(config) {
|
|
464
|
+
validateConfig(config);
|
|
465
|
+
const endpoints = resolveEndpoints(config.region);
|
|
466
|
+
const userClient = new ContentstackHttpClient({ baseUrl: `${endpoints.cma}/v3` });
|
|
467
|
+
return {
|
|
468
|
+
id: "contentstack",
|
|
469
|
+
name: "Contentstack",
|
|
470
|
+
type: "oauth",
|
|
471
|
+
checks: ["state"],
|
|
472
|
+
authorization: {
|
|
473
|
+
url: `${endpoints.app}/apps/${config.appId}/authorize`,
|
|
474
|
+
params: {
|
|
475
|
+
response_type: "code",
|
|
476
|
+
scope: config.scopes.join(" ")
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
token: `${endpoints.app}/apps-api/token`,
|
|
480
|
+
userinfo: {
|
|
481
|
+
url: `${endpoints.cma}/v3/user`,
|
|
482
|
+
async request({ tokens }) {
|
|
483
|
+
const authedClient = userClient.withHeaders({
|
|
484
|
+
Authorization: `Bearer ${tokens.access_token}`
|
|
485
|
+
});
|
|
486
|
+
const { data } = await authedClient.get("/user");
|
|
487
|
+
return data;
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
profile(profile) {
|
|
491
|
+
const user = profile.user;
|
|
492
|
+
return {
|
|
493
|
+
id: user.uid,
|
|
494
|
+
name: [user.first_name, user.last_name].filter(Boolean).join(" ") || user.username,
|
|
495
|
+
email: user.email,
|
|
496
|
+
image: user.profile_image ?? null
|
|
497
|
+
};
|
|
498
|
+
},
|
|
499
|
+
clientId: config.clientId,
|
|
500
|
+
clientSecret: config.clientSecret
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function contentstackAuthCallbacks(config) {
|
|
504
|
+
return {
|
|
505
|
+
async jwt({
|
|
506
|
+
token,
|
|
507
|
+
account
|
|
508
|
+
}) {
|
|
509
|
+
if (account) {
|
|
510
|
+
token.accessToken = account.access_token;
|
|
511
|
+
token.refreshToken = account.refresh_token;
|
|
512
|
+
token.accessTokenExpiresAt = Date.now() + (account.expires_in ?? 3600) * 1e3;
|
|
513
|
+
return token;
|
|
514
|
+
}
|
|
515
|
+
const expiresAt = token.accessTokenExpiresAt;
|
|
516
|
+
if (expiresAt && Date.now() < expiresAt - 6e4) {
|
|
517
|
+
return token;
|
|
518
|
+
}
|
|
519
|
+
const currentRefreshToken = token.refreshToken;
|
|
520
|
+
if (!currentRefreshToken) {
|
|
521
|
+
token.error = "RefreshAccessTokenError";
|
|
522
|
+
return token;
|
|
523
|
+
}
|
|
524
|
+
try {
|
|
525
|
+
const tokens = await refreshToken(config, currentRefreshToken);
|
|
526
|
+
token.accessToken = tokens.accessToken;
|
|
527
|
+
token.refreshToken = tokens.refreshToken;
|
|
528
|
+
token.accessTokenExpiresAt = Date.now() + tokens.expiresIn * 1e3;
|
|
529
|
+
token.error = void 0;
|
|
530
|
+
} catch {
|
|
531
|
+
token.error = "RefreshAccessTokenError";
|
|
532
|
+
}
|
|
533
|
+
return token;
|
|
534
|
+
},
|
|
535
|
+
async session({
|
|
536
|
+
session,
|
|
537
|
+
token
|
|
538
|
+
}) {
|
|
539
|
+
session.accessToken = token.accessToken;
|
|
540
|
+
if (token.error) {
|
|
541
|
+
session.error = token.error;
|
|
542
|
+
}
|
|
543
|
+
return session;
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// src/server/middleware/auth.ts
|
|
549
|
+
async function createContentstackAuth(config) {
|
|
550
|
+
const { default: NextAuth } = await import("next-auth");
|
|
551
|
+
const oauthConfig = {
|
|
552
|
+
region: config.region,
|
|
553
|
+
appId: config.appId,
|
|
554
|
+
clientId: config.clientId,
|
|
555
|
+
clientSecret: config.clientSecret,
|
|
556
|
+
scopes: config.scopes,
|
|
557
|
+
redirectUri: "auto"
|
|
558
|
+
};
|
|
559
|
+
const provider = createAuthProvider(oauthConfig);
|
|
560
|
+
const baseCallbacks = contentstackAuthCallbacks(oauthConfig);
|
|
561
|
+
const callbacks = {
|
|
562
|
+
async jwt(params) {
|
|
563
|
+
const token = await baseCallbacks.jwt(params);
|
|
564
|
+
if (params.account && config.onSignIn) {
|
|
565
|
+
try {
|
|
566
|
+
const user = await getUser(config.region, token.accessToken);
|
|
567
|
+
const tokens = {
|
|
568
|
+
accessToken: token.accessToken,
|
|
569
|
+
refreshToken: token.refreshToken,
|
|
570
|
+
expiresIn: Math.floor((token.accessTokenExpiresAt - Date.now()) / 1e3),
|
|
571
|
+
tokenType: "Bearer"
|
|
572
|
+
};
|
|
573
|
+
await config.onSignIn(user, tokens);
|
|
574
|
+
} catch {
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return token;
|
|
578
|
+
},
|
|
579
|
+
session: baseCallbacks.session
|
|
580
|
+
};
|
|
581
|
+
return NextAuth({
|
|
582
|
+
providers: [provider],
|
|
583
|
+
callbacks,
|
|
584
|
+
secret: config.secret,
|
|
585
|
+
trustHost: config.trustHost ?? true,
|
|
586
|
+
session: { strategy: "jwt" },
|
|
587
|
+
pages: {
|
|
588
|
+
signIn: config.signInPage ?? "/login",
|
|
589
|
+
error: config.errorPage ?? "/login"
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/server/middleware/session.ts
|
|
595
|
+
async function getSession(authFn) {
|
|
596
|
+
const session = await authFn();
|
|
597
|
+
if (!session?.accessToken) return null;
|
|
598
|
+
return { accessToken: session.accessToken, user: session.user };
|
|
599
|
+
}
|
|
600
|
+
async function requireSession(authFn, redirectTo) {
|
|
601
|
+
const session = await getSession(authFn);
|
|
602
|
+
if (!session) {
|
|
603
|
+
throw new ContentstackAuthError(
|
|
604
|
+
redirectTo ? `Authentication required. Redirect to: ${redirectTo}` : "Authentication required",
|
|
605
|
+
{ status: 401 }
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
return session;
|
|
609
|
+
}
|
|
610
|
+
async function getAccessToken(authFn) {
|
|
611
|
+
const session = await authFn();
|
|
612
|
+
return session?.accessToken ?? null;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/server/proxy/proxy-base.ts
|
|
616
|
+
function jsonErrorResponse(error, status) {
|
|
617
|
+
return new Response(JSON.stringify({ error }), {
|
|
618
|
+
status,
|
|
619
|
+
headers: { "Content-Type": "application/json" }
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
function createBaseProxy(config, handleRequest) {
|
|
623
|
+
return async (request) => {
|
|
624
|
+
const token = await config.getAccessToken(request);
|
|
625
|
+
if (!token) {
|
|
626
|
+
return jsonErrorResponse("Unauthorized", 401);
|
|
627
|
+
}
|
|
628
|
+
const url = new URL(request.url);
|
|
629
|
+
const apiPath = url.pathname.replace(config.basePath, "");
|
|
630
|
+
const body = ["GET", "HEAD"].includes(request.method) || request.body === null ? void 0 : await request.arrayBuffer();
|
|
631
|
+
return handleRequest({
|
|
632
|
+
token,
|
|
633
|
+
apiPath,
|
|
634
|
+
search: url.search,
|
|
635
|
+
method: request.method,
|
|
636
|
+
body,
|
|
637
|
+
request
|
|
638
|
+
});
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
async function forwardRequest(url, method, headers, body, timeout) {
|
|
642
|
+
try {
|
|
643
|
+
const upstream = await fetch(url, {
|
|
644
|
+
method,
|
|
645
|
+
headers,
|
|
646
|
+
body,
|
|
647
|
+
signal: AbortSignal.timeout(timeout)
|
|
648
|
+
});
|
|
649
|
+
return new Response(upstream.body, {
|
|
650
|
+
status: upstream.status,
|
|
651
|
+
headers: {
|
|
652
|
+
"content-type": upstream.headers.get("content-type") ?? "application/json"
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
} catch {
|
|
656
|
+
return jsonErrorResponse("Bad Gateway", 502);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/server/proxy/rate-limiter.ts
|
|
661
|
+
function createRateLimiter(maxRequests, windowMs = 6e4) {
|
|
662
|
+
const windows = /* @__PURE__ */ new Map();
|
|
663
|
+
return {
|
|
664
|
+
/**
|
|
665
|
+
* Check if the request is within rate limits.
|
|
666
|
+
* @returns `true` if the request is allowed, `false` if rate limited.
|
|
667
|
+
*/
|
|
668
|
+
check(key) {
|
|
669
|
+
const now = Date.now();
|
|
670
|
+
const window = windows.get(key);
|
|
671
|
+
for (const [k, w] of windows) {
|
|
672
|
+
if (now - w.windowStart > windowMs) {
|
|
673
|
+
windows.delete(k);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (!window || now - window.windowStart > windowMs) {
|
|
677
|
+
windows.set(key, { count: 1, windowStart: now });
|
|
678
|
+
return true;
|
|
679
|
+
}
|
|
680
|
+
window.count++;
|
|
681
|
+
return window.count <= maxRequests;
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/server/proxy/scope-guard.ts
|
|
687
|
+
var READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
688
|
+
function resolveScope(method, path) {
|
|
689
|
+
const isRead = READ_METHODS.has(method.toUpperCase());
|
|
690
|
+
const suffix = isRead ? ":read" : ":write";
|
|
691
|
+
const segments = path.split("/");
|
|
692
|
+
if (segments.includes("entries")) return `entries${suffix}`;
|
|
693
|
+
if (segments.includes("content_types")) return `content-types${suffix}`;
|
|
694
|
+
if (segments.includes("assets")) return `assets${suffix}`;
|
|
695
|
+
if (segments.includes("environments")) return "environments:read";
|
|
696
|
+
if (segments.includes("locales")) return "locales:read";
|
|
697
|
+
if (segments.includes("releases")) return `releases${suffix}`;
|
|
698
|
+
if (segments.includes("taxonomies")) return `taxonomies${suffix}`;
|
|
699
|
+
if (segments.includes("workflows")) return `workflows${suffix}`;
|
|
700
|
+
if (segments.includes("webhooks")) return `webhooks${suffix}`;
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
function checkScope(required, allowed) {
|
|
704
|
+
if (allowed.includes(required)) return null;
|
|
705
|
+
return `Scope "${required}" is not allowed. Allowed scopes: ${allowed.join(", ")}`;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// src/server/proxy/cma-proxy.ts
|
|
709
|
+
function createCMAProxy(config) {
|
|
710
|
+
const endpoints = resolveEndpoints(config.region);
|
|
711
|
+
const cmaBase = `${endpoints.cma}/v3`;
|
|
712
|
+
const timeout = config.timeout ?? 3e4;
|
|
713
|
+
const rateLimiter = config.rateLimit ? createRateLimiter(config.rateLimit) : null;
|
|
714
|
+
return createBaseProxy(
|
|
715
|
+
{
|
|
716
|
+
getAccessToken: config.getAccessToken,
|
|
717
|
+
basePath: config.basePath ?? "/api/cma",
|
|
718
|
+
timeout
|
|
719
|
+
},
|
|
720
|
+
async (ctx) => {
|
|
721
|
+
if (rateLimiter && !rateLimiter.check(ctx.token)) {
|
|
722
|
+
return jsonErrorResponse("Too Many Requests", 429);
|
|
723
|
+
}
|
|
724
|
+
if (config.allowedScopes) {
|
|
725
|
+
const scope = resolveScope(ctx.method, ctx.apiPath);
|
|
726
|
+
if (!scope) {
|
|
727
|
+
if ((config.unmappedScopeBehavior ?? "deny") === "deny") {
|
|
728
|
+
return jsonErrorResponse(
|
|
729
|
+
`No scope mapping found for "${ctx.method} ${ctx.apiPath}". Add a mapping or set unmappedScopeBehavior: "allow".`,
|
|
730
|
+
403
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
} else {
|
|
734
|
+
const rejection = checkScope(scope, config.allowedScopes);
|
|
735
|
+
if (rejection) {
|
|
736
|
+
return jsonErrorResponse(rejection, 403);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const headers = {
|
|
741
|
+
api_key: config.apiKey,
|
|
742
|
+
authorization: `Bearer ${ctx.token}`
|
|
743
|
+
};
|
|
744
|
+
const contentType = ctx.request.headers.get("content-type");
|
|
745
|
+
if (contentType) {
|
|
746
|
+
headers["content-type"] = contentType;
|
|
747
|
+
}
|
|
748
|
+
return forwardRequest(
|
|
749
|
+
cmaBase + ctx.apiPath + ctx.search,
|
|
750
|
+
ctx.method,
|
|
751
|
+
headers,
|
|
752
|
+
ctx.body,
|
|
753
|
+
timeout
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/server/proxy/launch-proxy.ts
|
|
760
|
+
function createLaunchProxy(config) {
|
|
761
|
+
const endpoints = resolveEndpoints(config.region);
|
|
762
|
+
const launchBase = endpoints.launch;
|
|
763
|
+
const timeout = config.timeout ?? 3e4;
|
|
764
|
+
return createBaseProxy(
|
|
765
|
+
{
|
|
766
|
+
getAccessToken: config.getAccessToken,
|
|
767
|
+
basePath: config.basePath ?? "/api/launch",
|
|
768
|
+
timeout
|
|
769
|
+
},
|
|
770
|
+
async (ctx) => {
|
|
771
|
+
const headers = {
|
|
772
|
+
authorization: `Bearer ${ctx.token}`,
|
|
773
|
+
organization_uid: config.organizationUid,
|
|
774
|
+
"content-type": "application/json"
|
|
775
|
+
};
|
|
776
|
+
return forwardRequest(
|
|
777
|
+
launchBase + ctx.apiPath + ctx.search,
|
|
778
|
+
ctx.method,
|
|
779
|
+
headers,
|
|
780
|
+
ctx.body,
|
|
781
|
+
timeout
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// src/server/proxy/brandkit-proxy.ts
|
|
788
|
+
function createBrandKitProxy(config) {
|
|
789
|
+
const endpoints = resolveEndpoints(config.region);
|
|
790
|
+
const brandKitBase = endpoints.brandKit;
|
|
791
|
+
const brandKitAIBase = endpoints.brandKitAI;
|
|
792
|
+
const timeout = config.timeout ?? 3e4;
|
|
793
|
+
return createBaseProxy(
|
|
794
|
+
{
|
|
795
|
+
getAccessToken: config.getAccessToken,
|
|
796
|
+
basePath: config.basePath ?? "/api/brandkit",
|
|
797
|
+
timeout
|
|
798
|
+
},
|
|
799
|
+
async (ctx) => {
|
|
800
|
+
if (config.allowedOperations?.length) {
|
|
801
|
+
const hasManage = config.allowedOperations.includes("manage");
|
|
802
|
+
if (!hasManage && !["GET", "HEAD"].includes(ctx.method)) {
|
|
803
|
+
return jsonErrorResponse("Forbidden: read-only mode", 403);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
const headers = {
|
|
807
|
+
authorization: `Bearer ${ctx.token}`,
|
|
808
|
+
organization_uid: config.organizationUid,
|
|
809
|
+
brand_kit_uid: config.brandKitUid,
|
|
810
|
+
"content-type": "application/json"
|
|
811
|
+
};
|
|
812
|
+
const isAIPath = ctx.apiPath.includes("/knowledge-vault") || ctx.apiPath.includes("/generative-ai");
|
|
813
|
+
const baseUrl = isAIPath ? brandKitAIBase : brandKitBase;
|
|
814
|
+
return forwardRequest(
|
|
815
|
+
baseUrl + ctx.apiPath + ctx.search,
|
|
816
|
+
ctx.method,
|
|
817
|
+
headers,
|
|
818
|
+
ctx.body,
|
|
819
|
+
timeout
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/server/webhooks/verify.ts
|
|
826
|
+
function hexDecode(hex) {
|
|
827
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
828
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
829
|
+
bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);
|
|
830
|
+
}
|
|
831
|
+
return bytes;
|
|
832
|
+
}
|
|
833
|
+
function timingSafeEqual(a, b) {
|
|
834
|
+
if (a.length !== b.length) return false;
|
|
835
|
+
let result = 0;
|
|
836
|
+
for (let i = 0; i < a.length; i++) {
|
|
837
|
+
result |= (a[i] ?? 0) ^ (b[i] ?? 0);
|
|
838
|
+
}
|
|
839
|
+
return result === 0;
|
|
840
|
+
}
|
|
841
|
+
async function verifyWebhookSignature(body, signature, secret) {
|
|
842
|
+
const encoder = new TextEncoder();
|
|
843
|
+
const key = await globalThis.crypto.subtle.importKey(
|
|
844
|
+
"raw",
|
|
845
|
+
encoder.encode(secret),
|
|
846
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
847
|
+
false,
|
|
848
|
+
["sign"]
|
|
849
|
+
);
|
|
850
|
+
const expectedBuffer = await globalThis.crypto.subtle.sign("HMAC", key, encoder.encode(body));
|
|
851
|
+
const expectedBytes = new Uint8Array(expectedBuffer);
|
|
852
|
+
const signatureBytes = hexDecode(signature);
|
|
853
|
+
return timingSafeEqual(expectedBytes, signatureBytes);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/server/webhooks/handler.ts
|
|
857
|
+
var SIGNATURE_HEADER = "x-contentstack-request-signature";
|
|
858
|
+
function parseWebhookBody(body) {
|
|
859
|
+
const raw = JSON.parse(body);
|
|
860
|
+
const module2 = raw.module;
|
|
861
|
+
const event = raw.event;
|
|
862
|
+
const type = `${module2}.${event}`;
|
|
863
|
+
return {
|
|
864
|
+
...raw,
|
|
865
|
+
type,
|
|
866
|
+
module: module2,
|
|
867
|
+
event
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
function createWebhookHandler(config) {
|
|
871
|
+
return {
|
|
872
|
+
/**
|
|
873
|
+
* Read the request body, verify the signature, and return a typed event.
|
|
874
|
+
* Throws `ContentstackAuthError` if the signature is missing or invalid.
|
|
875
|
+
*/
|
|
876
|
+
async verify(request) {
|
|
877
|
+
const body = await request.text();
|
|
878
|
+
const signature = request.headers.get(SIGNATURE_HEADER);
|
|
879
|
+
if (!signature) {
|
|
880
|
+
throw new ContentstackAuthError("Missing webhook signature header", {
|
|
881
|
+
status: 401,
|
|
882
|
+
requestPath: new URL(request.url).pathname
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
const valid = await verifyWebhookSignature(body, signature, config.secret);
|
|
886
|
+
if (!valid) {
|
|
887
|
+
throw new ContentstackAuthError("Invalid webhook signature", {
|
|
888
|
+
status: 401,
|
|
889
|
+
requestPath: new URL(request.url).pathname
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
return parseWebhookBody(body);
|
|
893
|
+
},
|
|
894
|
+
/**
|
|
895
|
+
* Read the request body and return a typed event without verifying the signature.
|
|
896
|
+
*/
|
|
897
|
+
async parse(request) {
|
|
898
|
+
const body = await request.text();
|
|
899
|
+
return parseWebhookBody(body);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
904
|
+
0 && (module.exports = {
|
|
905
|
+
checkScope,
|
|
906
|
+
createBrandKitProxy,
|
|
907
|
+
createCMAProxy,
|
|
908
|
+
createContentstackAuth,
|
|
909
|
+
createLaunchProxy,
|
|
910
|
+
createWebhookHandler,
|
|
911
|
+
getAccessToken,
|
|
912
|
+
getSession,
|
|
913
|
+
requireSession,
|
|
914
|
+
resolveScope,
|
|
915
|
+
verifyWebhookSignature
|
|
916
|
+
});
|
|
917
|
+
//# sourceMappingURL=index.cjs.map
|