@uniformdev/mesh-edgehancer-sdk 19.121.0 → 19.122.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as zod from 'zod';
2
2
  import { z } from 'zod';
3
3
  import { DataType, DataSource } from '@uniformdev/canvas';
4
+ import { NextApiRequest, NextApiResponse } from 'next';
4
5
 
5
6
  /**
6
7
  * The context we are fetching the data resource in:
@@ -292,6 +293,45 @@ type ResolveBatchIdsResult<TID> = {
292
293
  */
293
294
  declare function resolveBatchFetchIds<TID>(batch: readonly RequestEdgehancerDataResourceContext[], resolveBatchItemIdFn: (dataResource: RequestEdgehancerDataResourceContext) => TID | undefined): ResolveBatchIdsResult<TID>;
294
295
 
296
+ type InvalidationResponse = {
297
+ status: number;
298
+ text: string;
299
+ };
300
+ declare abstract class APIError extends Error {
301
+ abstract readonly status: number;
302
+ abstract readonly statusText: string;
303
+ }
304
+ declare class BadRequestError extends APIError {
305
+ status: number;
306
+ statusText: string;
307
+ constructor(message?: string);
308
+ }
309
+ declare class ForbiddenError extends APIError {
310
+ status: number;
311
+ statusText: string;
312
+ constructor(message?: string);
313
+ }
314
+
315
+ type Purger = {
316
+ purgeAllCachesForDataType(): Promise<InvalidationResponse>;
317
+ purgeBySurrogateKeys(surrogateKeys: string[]): Promise<InvalidationResponse>;
318
+ };
319
+ declare const createPurger: ({ invalidationEndpointUrl }: {
320
+ invalidationEndpointUrl: URL;
321
+ }) => Purger;
322
+
323
+ type Handler = (args: {
324
+ request: NextApiRequest;
325
+ purger: Purger;
326
+ }) => Promise<InvalidationResponse>;
327
+ declare const handleWebhookRequest: (req: NextApiRequest, res: NextApiResponse, handler: Handler) => Promise<void>;
328
+
329
+ declare function getParam(query: NextApiRequest['query'], paramName: string): string | null;
330
+ declare function getRequiredParam(query: NextApiRequest['query'], paramName: string): string;
331
+ declare function validateParams(req: NextApiRequest): {
332
+ invalidationEndpointUrl: URL;
333
+ };
334
+
295
335
  declare const edgehancerMergedDataTypeSchema: z.ZodObject<Omit<{
296
336
  id: z.ZodString;
297
337
  displayName: z.ZodString;
@@ -820,4 +860,4 @@ declare function getDataResourceQueryString({ parameters, url }: EdgehancerMerge
820
860
  /** Gets the HTTP headers for a data resource */
821
861
  declare function getDataResourceHeaders({ headers }: EdgehancerMergedDataType): Headers;
822
862
 
823
- export { type ConvertBatchResultsToEdgehancerResultOptions, type CustomEdgehancerDefinition, type DataResource, type DataResourceFetchContext, type EdgehancerMergedDataType, type MergedDataType, type PreRequestEdgehancerContext, type PreRequestEdgehancerDataResourceContext, type PreRequestEdgehancerDataResourceResult, type PreRequestEdgehancerResult, type PreRequestHookFn, type RequestEdgehancerContext, type RequestEdgehancerDataResourceContext, type RequestEdgehancerDataResourceResolutionResult, type RequestEdgehancerResult, type RequestHookFn, type ResolveBatchIdsResult, convertBatchResultsToEdgehancerResult, dataResourceSchema, edgehancerMergedDataTypeSchema, getDataResourceAsRequest, getDataResourceHeaders, getDataResourceQueryString, getDataResourceUrl, mergedDataTypeSchema, preRequestEdgehancerDataResourceResultSchema, preRequestEdgehancerResultSchema, requestEdgehancerDataResourceResolutionResultSchema, requestEdgehancerResultSchema, resolveBatchFetchIds };
863
+ export { APIError, BadRequestError, type ConvertBatchResultsToEdgehancerResultOptions, type CustomEdgehancerDefinition, type DataResource, type DataResourceFetchContext, type EdgehancerMergedDataType, ForbiddenError, type InvalidationResponse, type MergedDataType, type PreRequestEdgehancerContext, type PreRequestEdgehancerDataResourceContext, type PreRequestEdgehancerDataResourceResult, type PreRequestEdgehancerResult, type PreRequestHookFn, type Purger, type RequestEdgehancerContext, type RequestEdgehancerDataResourceContext, type RequestEdgehancerDataResourceResolutionResult, type RequestEdgehancerResult, type RequestHookFn, type ResolveBatchIdsResult, convertBatchResultsToEdgehancerResult, createPurger, dataResourceSchema, edgehancerMergedDataTypeSchema, getDataResourceAsRequest, getDataResourceHeaders, getDataResourceQueryString, getDataResourceUrl, getParam, getRequiredParam, handleWebhookRequest, mergedDataTypeSchema, preRequestEdgehancerDataResourceResultSchema, preRequestEdgehancerResultSchema, requestEdgehancerDataResourceResolutionResultSchema, requestEdgehancerResultSchema, resolveBatchFetchIds, validateParams };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as zod from 'zod';
2
2
  import { z } from 'zod';
3
3
  import { DataType, DataSource } from '@uniformdev/canvas';
4
+ import { NextApiRequest, NextApiResponse } from 'next';
4
5
 
5
6
  /**
6
7
  * The context we are fetching the data resource in:
@@ -292,6 +293,45 @@ type ResolveBatchIdsResult<TID> = {
292
293
  */
293
294
  declare function resolveBatchFetchIds<TID>(batch: readonly RequestEdgehancerDataResourceContext[], resolveBatchItemIdFn: (dataResource: RequestEdgehancerDataResourceContext) => TID | undefined): ResolveBatchIdsResult<TID>;
294
295
 
296
+ type InvalidationResponse = {
297
+ status: number;
298
+ text: string;
299
+ };
300
+ declare abstract class APIError extends Error {
301
+ abstract readonly status: number;
302
+ abstract readonly statusText: string;
303
+ }
304
+ declare class BadRequestError extends APIError {
305
+ status: number;
306
+ statusText: string;
307
+ constructor(message?: string);
308
+ }
309
+ declare class ForbiddenError extends APIError {
310
+ status: number;
311
+ statusText: string;
312
+ constructor(message?: string);
313
+ }
314
+
315
+ type Purger = {
316
+ purgeAllCachesForDataType(): Promise<InvalidationResponse>;
317
+ purgeBySurrogateKeys(surrogateKeys: string[]): Promise<InvalidationResponse>;
318
+ };
319
+ declare const createPurger: ({ invalidationEndpointUrl }: {
320
+ invalidationEndpointUrl: URL;
321
+ }) => Purger;
322
+
323
+ type Handler = (args: {
324
+ request: NextApiRequest;
325
+ purger: Purger;
326
+ }) => Promise<InvalidationResponse>;
327
+ declare const handleWebhookRequest: (req: NextApiRequest, res: NextApiResponse, handler: Handler) => Promise<void>;
328
+
329
+ declare function getParam(query: NextApiRequest['query'], paramName: string): string | null;
330
+ declare function getRequiredParam(query: NextApiRequest['query'], paramName: string): string;
331
+ declare function validateParams(req: NextApiRequest): {
332
+ invalidationEndpointUrl: URL;
333
+ };
334
+
295
335
  declare const edgehancerMergedDataTypeSchema: z.ZodObject<Omit<{
296
336
  id: z.ZodString;
297
337
  displayName: z.ZodString;
@@ -820,4 +860,4 @@ declare function getDataResourceQueryString({ parameters, url }: EdgehancerMerge
820
860
  /** Gets the HTTP headers for a data resource */
821
861
  declare function getDataResourceHeaders({ headers }: EdgehancerMergedDataType): Headers;
822
862
 
823
- export { type ConvertBatchResultsToEdgehancerResultOptions, type CustomEdgehancerDefinition, type DataResource, type DataResourceFetchContext, type EdgehancerMergedDataType, type MergedDataType, type PreRequestEdgehancerContext, type PreRequestEdgehancerDataResourceContext, type PreRequestEdgehancerDataResourceResult, type PreRequestEdgehancerResult, type PreRequestHookFn, type RequestEdgehancerContext, type RequestEdgehancerDataResourceContext, type RequestEdgehancerDataResourceResolutionResult, type RequestEdgehancerResult, type RequestHookFn, type ResolveBatchIdsResult, convertBatchResultsToEdgehancerResult, dataResourceSchema, edgehancerMergedDataTypeSchema, getDataResourceAsRequest, getDataResourceHeaders, getDataResourceQueryString, getDataResourceUrl, mergedDataTypeSchema, preRequestEdgehancerDataResourceResultSchema, preRequestEdgehancerResultSchema, requestEdgehancerDataResourceResolutionResultSchema, requestEdgehancerResultSchema, resolveBatchFetchIds };
863
+ export { APIError, BadRequestError, type ConvertBatchResultsToEdgehancerResultOptions, type CustomEdgehancerDefinition, type DataResource, type DataResourceFetchContext, type EdgehancerMergedDataType, ForbiddenError, type InvalidationResponse, type MergedDataType, type PreRequestEdgehancerContext, type PreRequestEdgehancerDataResourceContext, type PreRequestEdgehancerDataResourceResult, type PreRequestEdgehancerResult, type PreRequestHookFn, type Purger, type RequestEdgehancerContext, type RequestEdgehancerDataResourceContext, type RequestEdgehancerDataResourceResolutionResult, type RequestEdgehancerResult, type RequestHookFn, type ResolveBatchIdsResult, convertBatchResultsToEdgehancerResult, createPurger, dataResourceSchema, edgehancerMergedDataTypeSchema, getDataResourceAsRequest, getDataResourceHeaders, getDataResourceQueryString, getDataResourceUrl, getParam, getRequiredParam, handleWebhookRequest, mergedDataTypeSchema, preRequestEdgehancerDataResourceResultSchema, preRequestEdgehancerResultSchema, requestEdgehancerDataResourceResolutionResultSchema, requestEdgehancerResultSchema, resolveBatchFetchIds, validateParams };
package/dist/index.esm.js CHANGED
@@ -52,6 +52,156 @@ function resolveBatchFetchIds(batch, resolveBatchItemIdFn) {
52
52
  return result;
53
53
  }
54
54
 
55
+ // src/cache-purging-webhooks/purge.ts
56
+ var logger = console;
57
+ var createPurger = ({ invalidationEndpointUrl }) => {
58
+ logger.log(`[createPurger] call`, {
59
+ invalidationEndpointUrl: invalidationEndpointUrl.toString()
60
+ });
61
+ const purgeAllCachesForDataType = async () => {
62
+ logger.log(`[purgeAllCachesForDataType] call`, {
63
+ invalidationEndpointUrl: invalidationEndpointUrl.toString()
64
+ });
65
+ const res = await fetch(invalidationEndpointUrl, {
66
+ method: "GET"
67
+ });
68
+ return {
69
+ status: res.status,
70
+ text: await res.text()
71
+ };
72
+ };
73
+ const purgeBySurrogateKeys = async (surrogateKeys) => {
74
+ logger.log(`[purgeBySurrogateKeys] call`, {
75
+ invalidationEndpointUrl: invalidationEndpointUrl.toString(),
76
+ surrogateKeys
77
+ });
78
+ const body = {
79
+ surrogateKeys: surrogateKeys.filter((x) => x)
80
+ };
81
+ if (body.surrogateKeys.length > 0) {
82
+ const res = await fetch(invalidationEndpointUrl, {
83
+ method: "POST",
84
+ body: JSON.stringify(body)
85
+ });
86
+ return {
87
+ status: res.status,
88
+ text: await res.text()
89
+ };
90
+ } else {
91
+ logger.log(`[purgeBySurrogateKeys] No surrogate keys found.`, {
92
+ invalidationEndpointUrl: invalidationEndpointUrl.toString(),
93
+ surrogateKeys
94
+ });
95
+ return {
96
+ status: 200,
97
+ text: "No surrogate keys found."
98
+ };
99
+ }
100
+ };
101
+ return { purgeAllCachesForDataType, purgeBySurrogateKeys };
102
+ };
103
+
104
+ // src/cache-purging-webhooks/shared.ts
105
+ var APIError = class extends Error {
106
+ };
107
+ var BadRequestError = class _BadRequestError extends APIError {
108
+ constructor(message = "Invalid request received") {
109
+ super(message);
110
+ this.status = 400;
111
+ this.statusText = "Bad Request";
112
+ Object.setPrototypeOf(this, _BadRequestError.prototype);
113
+ }
114
+ };
115
+ var ForbiddenError = class _ForbiddenError extends APIError {
116
+ constructor(message = "This action is forbidden") {
117
+ super(message);
118
+ this.status = 403;
119
+ this.statusText = "Forbidden";
120
+ Object.setPrototypeOf(this, _ForbiddenError.prototype);
121
+ }
122
+ };
123
+
124
+ // src/cache-purging-webhooks/utils.ts
125
+ function getParam(query, paramName) {
126
+ const values = query[paramName];
127
+ if (!values) {
128
+ return null;
129
+ } else if (typeof values === "string") {
130
+ return values;
131
+ } else if (values.length === 1) {
132
+ return values[0];
133
+ } else {
134
+ throw new BadRequestError(`Multiple values for ${paramName} found in request parameters`);
135
+ }
136
+ }
137
+ function getRequiredParam(query, paramName) {
138
+ const value = getParam(query, paramName);
139
+ if (!value) {
140
+ throw new BadRequestError(`${paramName} not found in request parameters`);
141
+ }
142
+ return value;
143
+ }
144
+ function validateParams(req) {
145
+ const edgeApiHost = getParam(req.query, "edgeApiHost");
146
+ if (edgeApiHost) {
147
+ if (!isAllowedEdgeApiHost(edgeApiHost)) {
148
+ throw new ForbiddenError(`Edge API hostname is not allowed: ${edgeApiHost}`);
149
+ }
150
+ }
151
+ const projectId = getRequiredParam(req.query, "projectId");
152
+ const dataTypeId = getRequiredParam(req.query, "dataTypeId");
153
+ const purgeKey = getRequiredParam(req.query, "purgeKey");
154
+ const invalidationEndpointUrl = new URL(`https://${edgeApiHost || "uniform.global"}/api/v1/invalidation`);
155
+ invalidationEndpointUrl.searchParams.set("projectId", projectId);
156
+ invalidationEndpointUrl.searchParams.set("dataTypeId", dataTypeId);
157
+ invalidationEndpointUrl.searchParams.set("purgeKey", purgeKey);
158
+ return { invalidationEndpointUrl };
159
+ }
160
+ function isAllowedEdgeApiHost(edgeApiHost) {
161
+ if (["uniform.global", "canary.uniform.global"].includes(edgeApiHost)) {
162
+ return true;
163
+ }
164
+ if (edgeApiHost.endsWith(".uniform.rocks")) {
165
+ return true;
166
+ }
167
+ return false;
168
+ }
169
+
170
+ // src/cache-purging-webhooks/handleWebhookRequest.ts
171
+ var ALLOWED_METHODS = ["POST"];
172
+ var logger2 = console;
173
+ var handleWebhookRequest = async (req, res, handler) => {
174
+ try {
175
+ logger2.log(`request`, {
176
+ url: req.url,
177
+ method: req.method
178
+ });
179
+ if (!ALLOWED_METHODS.includes(req.method || "")) {
180
+ throw new BadRequestError(`Expected ${ALLOWED_METHODS.join(" or ")} but was called with ${req.method}`);
181
+ }
182
+ const { invalidationEndpointUrl } = validateParams(req);
183
+ const purger = createPurger({ invalidationEndpointUrl });
184
+ const { status, text } = await handler({
185
+ request: req,
186
+ purger
187
+ });
188
+ res.status(status).send(text);
189
+ } catch (err) {
190
+ if (err instanceof APIError) {
191
+ logger2.error(`APIError: [${err.status} ${err.statusText}] ${err.message}`);
192
+ res.status(err.status).json({
193
+ type: err.statusText,
194
+ errorMessage: err.message
195
+ });
196
+ } else {
197
+ logger2.error(`Error`, err);
198
+ res.status(500).json({
199
+ errorMessage: err.message || "Unknown error"
200
+ });
201
+ }
202
+ }
203
+ };
204
+
55
205
  // src/fetchUtils.ts
56
206
  function getDataResourceAsRequest(data) {
57
207
  var _a;
@@ -178,17 +328,25 @@ var requestEdgehancerResultSchema = z3.strictObject({
178
328
  results: z3.array(requestEdgehancerDataResourceResolutionResultSchema)
179
329
  });
180
330
  export {
331
+ APIError,
332
+ BadRequestError,
333
+ ForbiddenError,
181
334
  convertBatchResultsToEdgehancerResult,
335
+ createPurger,
182
336
  dataResourceSchema,
183
337
  edgehancerMergedDataTypeSchema,
184
338
  getDataResourceAsRequest,
185
339
  getDataResourceHeaders,
186
340
  getDataResourceQueryString,
187
341
  getDataResourceUrl,
342
+ getParam,
343
+ getRequiredParam,
344
+ handleWebhookRequest,
188
345
  mergedDataTypeSchema,
189
346
  preRequestEdgehancerDataResourceResultSchema,
190
347
  preRequestEdgehancerResultSchema,
191
348
  requestEdgehancerDataResourceResolutionResultSchema,
192
349
  requestEdgehancerResultSchema,
193
- resolveBatchFetchIds
350
+ resolveBatchFetchIds,
351
+ validateParams
194
352
  };
package/dist/index.js CHANGED
@@ -20,19 +20,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ APIError: () => APIError,
24
+ BadRequestError: () => BadRequestError,
25
+ ForbiddenError: () => ForbiddenError,
23
26
  convertBatchResultsToEdgehancerResult: () => convertBatchResultsToEdgehancerResult,
27
+ createPurger: () => createPurger,
24
28
  dataResourceSchema: () => dataResourceSchema,
25
29
  edgehancerMergedDataTypeSchema: () => edgehancerMergedDataTypeSchema,
26
30
  getDataResourceAsRequest: () => getDataResourceAsRequest,
27
31
  getDataResourceHeaders: () => getDataResourceHeaders,
28
32
  getDataResourceQueryString: () => getDataResourceQueryString,
29
33
  getDataResourceUrl: () => getDataResourceUrl,
34
+ getParam: () => getParam,
35
+ getRequiredParam: () => getRequiredParam,
36
+ handleWebhookRequest: () => handleWebhookRequest,
30
37
  mergedDataTypeSchema: () => mergedDataTypeSchema,
31
38
  preRequestEdgehancerDataResourceResultSchema: () => preRequestEdgehancerDataResourceResultSchema,
32
39
  preRequestEdgehancerResultSchema: () => preRequestEdgehancerResultSchema,
33
40
  requestEdgehancerDataResourceResolutionResultSchema: () => requestEdgehancerDataResourceResolutionResultSchema,
34
41
  requestEdgehancerResultSchema: () => requestEdgehancerResultSchema,
35
- resolveBatchFetchIds: () => resolveBatchFetchIds
42
+ resolveBatchFetchIds: () => resolveBatchFetchIds,
43
+ validateParams: () => validateParams
36
44
  });
37
45
  module.exports = __toCommonJS(src_exports);
38
46
 
@@ -90,6 +98,156 @@ function resolveBatchFetchIds(batch, resolveBatchItemIdFn) {
90
98
  return result;
91
99
  }
92
100
 
101
+ // src/cache-purging-webhooks/purge.ts
102
+ var logger = console;
103
+ var createPurger = ({ invalidationEndpointUrl }) => {
104
+ logger.log(`[createPurger] call`, {
105
+ invalidationEndpointUrl: invalidationEndpointUrl.toString()
106
+ });
107
+ const purgeAllCachesForDataType = async () => {
108
+ logger.log(`[purgeAllCachesForDataType] call`, {
109
+ invalidationEndpointUrl: invalidationEndpointUrl.toString()
110
+ });
111
+ const res = await fetch(invalidationEndpointUrl, {
112
+ method: "GET"
113
+ });
114
+ return {
115
+ status: res.status,
116
+ text: await res.text()
117
+ };
118
+ };
119
+ const purgeBySurrogateKeys = async (surrogateKeys) => {
120
+ logger.log(`[purgeBySurrogateKeys] call`, {
121
+ invalidationEndpointUrl: invalidationEndpointUrl.toString(),
122
+ surrogateKeys
123
+ });
124
+ const body = {
125
+ surrogateKeys: surrogateKeys.filter((x) => x)
126
+ };
127
+ if (body.surrogateKeys.length > 0) {
128
+ const res = await fetch(invalidationEndpointUrl, {
129
+ method: "POST",
130
+ body: JSON.stringify(body)
131
+ });
132
+ return {
133
+ status: res.status,
134
+ text: await res.text()
135
+ };
136
+ } else {
137
+ logger.log(`[purgeBySurrogateKeys] No surrogate keys found.`, {
138
+ invalidationEndpointUrl: invalidationEndpointUrl.toString(),
139
+ surrogateKeys
140
+ });
141
+ return {
142
+ status: 200,
143
+ text: "No surrogate keys found."
144
+ };
145
+ }
146
+ };
147
+ return { purgeAllCachesForDataType, purgeBySurrogateKeys };
148
+ };
149
+
150
+ // src/cache-purging-webhooks/shared.ts
151
+ var APIError = class extends Error {
152
+ };
153
+ var BadRequestError = class _BadRequestError extends APIError {
154
+ constructor(message = "Invalid request received") {
155
+ super(message);
156
+ this.status = 400;
157
+ this.statusText = "Bad Request";
158
+ Object.setPrototypeOf(this, _BadRequestError.prototype);
159
+ }
160
+ };
161
+ var ForbiddenError = class _ForbiddenError extends APIError {
162
+ constructor(message = "This action is forbidden") {
163
+ super(message);
164
+ this.status = 403;
165
+ this.statusText = "Forbidden";
166
+ Object.setPrototypeOf(this, _ForbiddenError.prototype);
167
+ }
168
+ };
169
+
170
+ // src/cache-purging-webhooks/utils.ts
171
+ function getParam(query, paramName) {
172
+ const values = query[paramName];
173
+ if (!values) {
174
+ return null;
175
+ } else if (typeof values === "string") {
176
+ return values;
177
+ } else if (values.length === 1) {
178
+ return values[0];
179
+ } else {
180
+ throw new BadRequestError(`Multiple values for ${paramName} found in request parameters`);
181
+ }
182
+ }
183
+ function getRequiredParam(query, paramName) {
184
+ const value = getParam(query, paramName);
185
+ if (!value) {
186
+ throw new BadRequestError(`${paramName} not found in request parameters`);
187
+ }
188
+ return value;
189
+ }
190
+ function validateParams(req) {
191
+ const edgeApiHost = getParam(req.query, "edgeApiHost");
192
+ if (edgeApiHost) {
193
+ if (!isAllowedEdgeApiHost(edgeApiHost)) {
194
+ throw new ForbiddenError(`Edge API hostname is not allowed: ${edgeApiHost}`);
195
+ }
196
+ }
197
+ const projectId = getRequiredParam(req.query, "projectId");
198
+ const dataTypeId = getRequiredParam(req.query, "dataTypeId");
199
+ const purgeKey = getRequiredParam(req.query, "purgeKey");
200
+ const invalidationEndpointUrl = new URL(`https://${edgeApiHost || "uniform.global"}/api/v1/invalidation`);
201
+ invalidationEndpointUrl.searchParams.set("projectId", projectId);
202
+ invalidationEndpointUrl.searchParams.set("dataTypeId", dataTypeId);
203
+ invalidationEndpointUrl.searchParams.set("purgeKey", purgeKey);
204
+ return { invalidationEndpointUrl };
205
+ }
206
+ function isAllowedEdgeApiHost(edgeApiHost) {
207
+ if (["uniform.global", "canary.uniform.global"].includes(edgeApiHost)) {
208
+ return true;
209
+ }
210
+ if (edgeApiHost.endsWith(".uniform.rocks")) {
211
+ return true;
212
+ }
213
+ return false;
214
+ }
215
+
216
+ // src/cache-purging-webhooks/handleWebhookRequest.ts
217
+ var ALLOWED_METHODS = ["POST"];
218
+ var logger2 = console;
219
+ var handleWebhookRequest = async (req, res, handler) => {
220
+ try {
221
+ logger2.log(`request`, {
222
+ url: req.url,
223
+ method: req.method
224
+ });
225
+ if (!ALLOWED_METHODS.includes(req.method || "")) {
226
+ throw new BadRequestError(`Expected ${ALLOWED_METHODS.join(" or ")} but was called with ${req.method}`);
227
+ }
228
+ const { invalidationEndpointUrl } = validateParams(req);
229
+ const purger = createPurger({ invalidationEndpointUrl });
230
+ const { status, text } = await handler({
231
+ request: req,
232
+ purger
233
+ });
234
+ res.status(status).send(text);
235
+ } catch (err) {
236
+ if (err instanceof APIError) {
237
+ logger2.error(`APIError: [${err.status} ${err.statusText}] ${err.message}`);
238
+ res.status(err.status).json({
239
+ type: err.statusText,
240
+ errorMessage: err.message
241
+ });
242
+ } else {
243
+ logger2.error(`Error`, err);
244
+ res.status(500).json({
245
+ errorMessage: err.message || "Unknown error"
246
+ });
247
+ }
248
+ }
249
+ };
250
+
93
251
  // src/fetchUtils.ts
94
252
  function getDataResourceAsRequest(data) {
95
253
  var _a;
@@ -217,17 +375,25 @@ var requestEdgehancerResultSchema = import_zod3.z.strictObject({
217
375
  });
218
376
  // Annotate the CommonJS export names for ESM import in node:
219
377
  0 && (module.exports = {
378
+ APIError,
379
+ BadRequestError,
380
+ ForbiddenError,
220
381
  convertBatchResultsToEdgehancerResult,
382
+ createPurger,
221
383
  dataResourceSchema,
222
384
  edgehancerMergedDataTypeSchema,
223
385
  getDataResourceAsRequest,
224
386
  getDataResourceHeaders,
225
387
  getDataResourceQueryString,
226
388
  getDataResourceUrl,
389
+ getParam,
390
+ getRequiredParam,
391
+ handleWebhookRequest,
227
392
  mergedDataTypeSchema,
228
393
  preRequestEdgehancerDataResourceResultSchema,
229
394
  preRequestEdgehancerResultSchema,
230
395
  requestEdgehancerDataResourceResolutionResultSchema,
231
396
  requestEdgehancerResultSchema,
232
- resolveBatchFetchIds
397
+ resolveBatchFetchIds,
398
+ validateParams
233
399
  });
package/dist/index.mjs CHANGED
@@ -52,6 +52,156 @@ function resolveBatchFetchIds(batch, resolveBatchItemIdFn) {
52
52
  return result;
53
53
  }
54
54
 
55
+ // src/cache-purging-webhooks/purge.ts
56
+ var logger = console;
57
+ var createPurger = ({ invalidationEndpointUrl }) => {
58
+ logger.log(`[createPurger] call`, {
59
+ invalidationEndpointUrl: invalidationEndpointUrl.toString()
60
+ });
61
+ const purgeAllCachesForDataType = async () => {
62
+ logger.log(`[purgeAllCachesForDataType] call`, {
63
+ invalidationEndpointUrl: invalidationEndpointUrl.toString()
64
+ });
65
+ const res = await fetch(invalidationEndpointUrl, {
66
+ method: "GET"
67
+ });
68
+ return {
69
+ status: res.status,
70
+ text: await res.text()
71
+ };
72
+ };
73
+ const purgeBySurrogateKeys = async (surrogateKeys) => {
74
+ logger.log(`[purgeBySurrogateKeys] call`, {
75
+ invalidationEndpointUrl: invalidationEndpointUrl.toString(),
76
+ surrogateKeys
77
+ });
78
+ const body = {
79
+ surrogateKeys: surrogateKeys.filter((x) => x)
80
+ };
81
+ if (body.surrogateKeys.length > 0) {
82
+ const res = await fetch(invalidationEndpointUrl, {
83
+ method: "POST",
84
+ body: JSON.stringify(body)
85
+ });
86
+ return {
87
+ status: res.status,
88
+ text: await res.text()
89
+ };
90
+ } else {
91
+ logger.log(`[purgeBySurrogateKeys] No surrogate keys found.`, {
92
+ invalidationEndpointUrl: invalidationEndpointUrl.toString(),
93
+ surrogateKeys
94
+ });
95
+ return {
96
+ status: 200,
97
+ text: "No surrogate keys found."
98
+ };
99
+ }
100
+ };
101
+ return { purgeAllCachesForDataType, purgeBySurrogateKeys };
102
+ };
103
+
104
+ // src/cache-purging-webhooks/shared.ts
105
+ var APIError = class extends Error {
106
+ };
107
+ var BadRequestError = class _BadRequestError extends APIError {
108
+ constructor(message = "Invalid request received") {
109
+ super(message);
110
+ this.status = 400;
111
+ this.statusText = "Bad Request";
112
+ Object.setPrototypeOf(this, _BadRequestError.prototype);
113
+ }
114
+ };
115
+ var ForbiddenError = class _ForbiddenError extends APIError {
116
+ constructor(message = "This action is forbidden") {
117
+ super(message);
118
+ this.status = 403;
119
+ this.statusText = "Forbidden";
120
+ Object.setPrototypeOf(this, _ForbiddenError.prototype);
121
+ }
122
+ };
123
+
124
+ // src/cache-purging-webhooks/utils.ts
125
+ function getParam(query, paramName) {
126
+ const values = query[paramName];
127
+ if (!values) {
128
+ return null;
129
+ } else if (typeof values === "string") {
130
+ return values;
131
+ } else if (values.length === 1) {
132
+ return values[0];
133
+ } else {
134
+ throw new BadRequestError(`Multiple values for ${paramName} found in request parameters`);
135
+ }
136
+ }
137
+ function getRequiredParam(query, paramName) {
138
+ const value = getParam(query, paramName);
139
+ if (!value) {
140
+ throw new BadRequestError(`${paramName} not found in request parameters`);
141
+ }
142
+ return value;
143
+ }
144
+ function validateParams(req) {
145
+ const edgeApiHost = getParam(req.query, "edgeApiHost");
146
+ if (edgeApiHost) {
147
+ if (!isAllowedEdgeApiHost(edgeApiHost)) {
148
+ throw new ForbiddenError(`Edge API hostname is not allowed: ${edgeApiHost}`);
149
+ }
150
+ }
151
+ const projectId = getRequiredParam(req.query, "projectId");
152
+ const dataTypeId = getRequiredParam(req.query, "dataTypeId");
153
+ const purgeKey = getRequiredParam(req.query, "purgeKey");
154
+ const invalidationEndpointUrl = new URL(`https://${edgeApiHost || "uniform.global"}/api/v1/invalidation`);
155
+ invalidationEndpointUrl.searchParams.set("projectId", projectId);
156
+ invalidationEndpointUrl.searchParams.set("dataTypeId", dataTypeId);
157
+ invalidationEndpointUrl.searchParams.set("purgeKey", purgeKey);
158
+ return { invalidationEndpointUrl };
159
+ }
160
+ function isAllowedEdgeApiHost(edgeApiHost) {
161
+ if (["uniform.global", "canary.uniform.global"].includes(edgeApiHost)) {
162
+ return true;
163
+ }
164
+ if (edgeApiHost.endsWith(".uniform.rocks")) {
165
+ return true;
166
+ }
167
+ return false;
168
+ }
169
+
170
+ // src/cache-purging-webhooks/handleWebhookRequest.ts
171
+ var ALLOWED_METHODS = ["POST"];
172
+ var logger2 = console;
173
+ var handleWebhookRequest = async (req, res, handler) => {
174
+ try {
175
+ logger2.log(`request`, {
176
+ url: req.url,
177
+ method: req.method
178
+ });
179
+ if (!ALLOWED_METHODS.includes(req.method || "")) {
180
+ throw new BadRequestError(`Expected ${ALLOWED_METHODS.join(" or ")} but was called with ${req.method}`);
181
+ }
182
+ const { invalidationEndpointUrl } = validateParams(req);
183
+ const purger = createPurger({ invalidationEndpointUrl });
184
+ const { status, text } = await handler({
185
+ request: req,
186
+ purger
187
+ });
188
+ res.status(status).send(text);
189
+ } catch (err) {
190
+ if (err instanceof APIError) {
191
+ logger2.error(`APIError: [${err.status} ${err.statusText}] ${err.message}`);
192
+ res.status(err.status).json({
193
+ type: err.statusText,
194
+ errorMessage: err.message
195
+ });
196
+ } else {
197
+ logger2.error(`Error`, err);
198
+ res.status(500).json({
199
+ errorMessage: err.message || "Unknown error"
200
+ });
201
+ }
202
+ }
203
+ };
204
+
55
205
  // src/fetchUtils.ts
56
206
  function getDataResourceAsRequest(data) {
57
207
  var _a;
@@ -178,17 +328,25 @@ var requestEdgehancerResultSchema = z3.strictObject({
178
328
  results: z3.array(requestEdgehancerDataResourceResolutionResultSchema)
179
329
  });
180
330
  export {
331
+ APIError,
332
+ BadRequestError,
333
+ ForbiddenError,
181
334
  convertBatchResultsToEdgehancerResult,
335
+ createPurger,
182
336
  dataResourceSchema,
183
337
  edgehancerMergedDataTypeSchema,
184
338
  getDataResourceAsRequest,
185
339
  getDataResourceHeaders,
186
340
  getDataResourceQueryString,
187
341
  getDataResourceUrl,
342
+ getParam,
343
+ getRequiredParam,
344
+ handleWebhookRequest,
188
345
  mergedDataTypeSchema,
189
346
  preRequestEdgehancerDataResourceResultSchema,
190
347
  preRequestEdgehancerResultSchema,
191
348
  requestEdgehancerDataResourceResolutionResultSchema,
192
349
  requestEdgehancerResultSchema,
193
- resolveBatchFetchIds
350
+ resolveBatchFetchIds,
351
+ validateParams
194
352
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/mesh-edgehancer-sdk",
3
- "version": "19.121.0",
3
+ "version": "19.122.1-alpha.0+03f737f1b5",
4
4
  "description": "Uniform Mesh Edgehancer SDK",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./dist/index.js",
@@ -28,12 +28,18 @@
28
28
  "/dist"
29
29
  ],
30
30
  "dependencies": {
31
- "@uniformdev/canvas": "19.121.0",
31
+ "@uniformdev/canvas": "19.122.1-alpha.0+03f737f1b5",
32
32
  "tsafe": "1.6.5",
33
33
  "zod": "3.22.4"
34
34
  },
35
+ "devDependencies": {
36
+ "next": "13.4.12"
37
+ },
38
+ "peerDependencies": {
39
+ "next": ">13"
40
+ },
35
41
  "publishConfig": {
36
42
  "access": "public"
37
43
  },
38
- "gitHead": "4bab305415aa38c7d473a08c15bcd78fcb7d8d88"
44
+ "gitHead": "03f737f1b507886971bc90dde2367d1bf85f5edf"
39
45
  }