@open-mercato/webhooks 0.4.9-canary-8c762104f0

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.
Files changed (60) hide show
  1. package/CLAUDE.md +1 -0
  2. package/build.mjs +69 -0
  3. package/dist/index.js +5 -0
  4. package/dist/index.js.map +7 -0
  5. package/dist/modules/webhooks/acl.js +14 -0
  6. package/dist/modules/webhooks/acl.js.map +7 -0
  7. package/dist/modules/webhooks/api/openapi.js +8 -0
  8. package/dist/modules/webhooks/api/openapi.js.map +7 -0
  9. package/dist/modules/webhooks/api/webhook-deliveries/route.js +118 -0
  10. package/dist/modules/webhooks/api/webhook-deliveries/route.js.map +7 -0
  11. package/dist/modules/webhooks/api/webhooks/route.js +268 -0
  12. package/dist/modules/webhooks/api/webhooks/route.js.map +7 -0
  13. package/dist/modules/webhooks/backend/webhooks/[id]/page.meta.js +17 -0
  14. package/dist/modules/webhooks/backend/webhooks/[id]/page.meta.js.map +7 -0
  15. package/dist/modules/webhooks/backend/webhooks/create/page.meta.js +17 -0
  16. package/dist/modules/webhooks/backend/webhooks/create/page.meta.js.map +7 -0
  17. package/dist/modules/webhooks/backend/webhooks/page.meta.js +24 -0
  18. package/dist/modules/webhooks/backend/webhooks/page.meta.js.map +7 -0
  19. package/dist/modules/webhooks/data/entities.js +196 -0
  20. package/dist/modules/webhooks/data/entities.js.map +7 -0
  21. package/dist/modules/webhooks/data/validators.js +39 -0
  22. package/dist/modules/webhooks/data/validators.js.map +7 -0
  23. package/dist/modules/webhooks/events.js +18 -0
  24. package/dist/modules/webhooks/events.js.map +7 -0
  25. package/dist/modules/webhooks/index.js +14 -0
  26. package/dist/modules/webhooks/index.js.map +7 -0
  27. package/dist/modules/webhooks/setup.js +12 -0
  28. package/dist/modules/webhooks/setup.js.map +7 -0
  29. package/dist/modules/webhooks/subscribers/outbound-dispatch.js +67 -0
  30. package/dist/modules/webhooks/subscribers/outbound-dispatch.js.map +7 -0
  31. package/dist/modules/webhooks/workers/webhook-delivery.js +129 -0
  32. package/dist/modules/webhooks/workers/webhook-delivery.js.map +7 -0
  33. package/generated/entities/webhook_delivery_entity/index.ts +22 -0
  34. package/generated/entities/webhook_entity/index.ts +26 -0
  35. package/generated/entities.ids.generated.ts +12 -0
  36. package/generated/entity-fields-registry.ts +13 -0
  37. package/jest.config.cjs +20 -0
  38. package/package.json +77 -0
  39. package/src/index.ts +1 -0
  40. package/src/modules/webhooks/acl.ts +10 -0
  41. package/src/modules/webhooks/api/openapi.ts +5 -0
  42. package/src/modules/webhooks/api/webhook-deliveries/route.ts +131 -0
  43. package/src/modules/webhooks/api/webhooks/route.ts +288 -0
  44. package/src/modules/webhooks/backend/webhooks/[id]/page.meta.ts +13 -0
  45. package/src/modules/webhooks/backend/webhooks/[id]/page.tsx +262 -0
  46. package/src/modules/webhooks/backend/webhooks/create/page.meta.ts +13 -0
  47. package/src/modules/webhooks/backend/webhooks/create/page.tsx +75 -0
  48. package/src/modules/webhooks/backend/webhooks/page.meta.ts +20 -0
  49. package/src/modules/webhooks/backend/webhooks/page.tsx +206 -0
  50. package/src/modules/webhooks/data/entities.ts +157 -0
  51. package/src/modules/webhooks/data/validators.ts +40 -0
  52. package/src/modules/webhooks/events.ts +15 -0
  53. package/src/modules/webhooks/i18n/en.json +73 -0
  54. package/src/modules/webhooks/index.ts +12 -0
  55. package/src/modules/webhooks/setup.ts +10 -0
  56. package/src/modules/webhooks/subscribers/outbound-dispatch.ts +79 -0
  57. package/src/modules/webhooks/workers/webhook-delivery.ts +158 -0
  58. package/tsconfig.build.json +13 -0
  59. package/tsconfig.json +9 -0
  60. package/watch.mjs +6 -0
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
package/build.mjs ADDED
@@ -0,0 +1,69 @@
1
+ import * as esbuild from 'esbuild'
2
+ import { glob } from 'glob'
3
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs'
4
+ import { dirname, join } from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url))
8
+
9
+ const entryPoints = await glob('src/**/*.ts', {
10
+ cwd: __dirname,
11
+ ignore: ['**/__tests__/**', '**/*.test.ts'],
12
+ absolute: true,
13
+ })
14
+
15
+ if (entryPoints.length === 0) {
16
+ console.error('No entry points found!')
17
+ process.exit(1)
18
+ }
19
+
20
+ console.log(`Found ${entryPoints.length} entry points`)
21
+
22
+ const addJsExtension = {
23
+ name: 'add-js-extension',
24
+ setup(build) {
25
+ build.onEnd(async (result) => {
26
+ if (result.errors.length > 0) return
27
+ const outputFiles = await glob('dist/**/*.js', { cwd: __dirname, absolute: true })
28
+ for (const file of outputFiles) {
29
+ const fileDir = dirname(file)
30
+ let content = readFileSync(file, 'utf-8')
31
+ content = content.replace(
32
+ /from\s+["'](\.[^"']+)["']/g,
33
+ (match, path) => {
34
+ if (path.endsWith('.js') || path.endsWith('.json')) return match
35
+ const resolvedPath = join(fileDir, path)
36
+ if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
37
+ return `from "${path}/index.js"`
38
+ }
39
+ return `from "${path}.js"`
40
+ }
41
+ )
42
+ content = content.replace(
43
+ /import\s*\(\s*["'](\.[^"']+)["']\s*\)/g,
44
+ (match, path) => {
45
+ if (path.endsWith('.js') || path.endsWith('.json')) return match
46
+ const resolvedPath = join(fileDir, path)
47
+ if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
48
+ return `import("${path}/index.js")`
49
+ }
50
+ return `import("${path}.js")`
51
+ }
52
+ )
53
+ writeFileSync(file, content)
54
+ }
55
+ })
56
+ }
57
+ }
58
+
59
+ await esbuild.build({
60
+ entryPoints,
61
+ outdir: 'dist',
62
+ format: 'esm',
63
+ platform: 'node',
64
+ target: 'node18',
65
+ sourcemap: true,
66
+ plugins: [addJsExtension],
67
+ })
68
+
69
+ console.log('webhooks built successfully')
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import { metadata } from "./modules/webhooks/index.js";
2
+ export {
3
+ metadata
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["export { metadata } from './modules/webhooks/index'\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,14 @@
1
+ const features = [
2
+ { id: "webhooks.view", title: "View webhooks", module: "webhooks" },
3
+ { id: "webhooks.create", title: "Create webhooks", module: "webhooks" },
4
+ { id: "webhooks.edit", title: "Edit webhooks", module: "webhooks" },
5
+ { id: "webhooks.delete", title: "Delete webhooks", module: "webhooks" },
6
+ { id: "webhooks.test", title: "Test webhooks", module: "webhooks" },
7
+ { id: "webhooks.deliveries.view", title: "View webhook deliveries", module: "webhooks" }
8
+ ];
9
+ var acl_default = features;
10
+ export {
11
+ acl_default as default,
12
+ features
13
+ };
14
+ //# sourceMappingURL=acl.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/webhooks/acl.ts"],
4
+ "sourcesContent": ["export const features = [\n { id: 'webhooks.view', title: 'View webhooks', module: 'webhooks' },\n { id: 'webhooks.create', title: 'Create webhooks', module: 'webhooks' },\n { id: 'webhooks.edit', title: 'Edit webhooks', module: 'webhooks' },\n { id: 'webhooks.delete', title: 'Delete webhooks', module: 'webhooks' },\n { id: 'webhooks.test', title: 'Test webhooks', module: 'webhooks' },\n { id: 'webhooks.deliveries.view', title: 'View webhook deliveries', module: 'webhooks' },\n]\n\nexport default features\n"],
5
+ "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,EAAE,IAAI,iBAAiB,OAAO,iBAAiB,QAAQ,WAAW;AAAA,EAClE,EAAE,IAAI,mBAAmB,OAAO,mBAAmB,QAAQ,WAAW;AAAA,EACtE,EAAE,IAAI,iBAAiB,OAAO,iBAAiB,QAAQ,WAAW;AAAA,EAClE,EAAE,IAAI,mBAAmB,OAAO,mBAAmB,QAAQ,WAAW;AAAA,EACtE,EAAE,IAAI,iBAAiB,OAAO,iBAAiB,QAAQ,WAAW;AAAA,EAClE,EAAE,IAAI,4BAA4B,OAAO,2BAA2B,QAAQ,WAAW;AACzF;AAEA,IAAO,cAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,8 @@
1
+ import { createCrudOpenApiFactory } from "@open-mercato/shared/lib/openapi/crud";
2
+ const buildWebhooksCrudOpenApi = createCrudOpenApiFactory({
3
+ defaultTag: "Webhooks"
4
+ });
5
+ export {
6
+ buildWebhooksCrudOpenApi
7
+ };
8
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/webhooks/api/openapi.ts"],
4
+ "sourcesContent": ["import { createCrudOpenApiFactory } from '@open-mercato/shared/lib/openapi/crud'\n\nexport const buildWebhooksCrudOpenApi = createCrudOpenApiFactory({\n defaultTag: 'Webhooks',\n})\n"],
5
+ "mappings": "AAAA,SAAS,gCAAgC;AAElC,MAAM,2BAA2B,yBAAyB;AAAA,EAC/D,YAAY;AACd,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,118 @@
1
+ import { z } from "zod";
2
+ import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
+ import { WebhookDeliveryEntity } from "../../data/entities.js";
4
+ import { webhookDeliveryQuerySchema } from "../../data/validators.js";
5
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
6
+ function json(payload, init = { status: 200 }) {
7
+ return new Response(JSON.stringify(payload), {
8
+ ...init,
9
+ headers: { "content-type": "application/json", ...init.headers || {} }
10
+ });
11
+ }
12
+ const deliveryItemSchema = z.object({
13
+ id: z.string(),
14
+ webhookId: z.string(),
15
+ eventType: z.string(),
16
+ messageId: z.string(),
17
+ status: z.string(),
18
+ responseStatus: z.number().nullable(),
19
+ errorMessage: z.string().nullable(),
20
+ attemptNumber: z.number(),
21
+ maxAttempts: z.number(),
22
+ targetUrl: z.string(),
23
+ durationMs: z.number().nullable(),
24
+ enqueuedAt: z.string(),
25
+ lastAttemptAt: z.string().nullable(),
26
+ deliveredAt: z.string().nullable(),
27
+ createdAt: z.string()
28
+ });
29
+ const deliveryCollectionResponseSchema = z.object({
30
+ items: z.array(deliveryItemSchema),
31
+ total: z.number().int().nonnegative(),
32
+ page: z.number().int().positive(),
33
+ pageSize: z.number().int().positive(),
34
+ totalPages: z.number().int().nonnegative()
35
+ });
36
+ const errorSchema = z.object({ error: z.string() });
37
+ const crud = makeCrudRoute({
38
+ metadata: {
39
+ GET: { requireAuth: true, requireFeatures: ["webhooks.deliveries.view"] }
40
+ },
41
+ orm: { entity: WebhookDeliveryEntity, orgField: "organizationId" },
42
+ list: { schema: webhookDeliveryQuerySchema },
43
+ hooks: {
44
+ beforeList: async (query, ctx) => {
45
+ const auth = ctx.auth;
46
+ const { translate } = await resolveTranslations();
47
+ if (!auth?.tenantId) throw json({ error: translate("webhooks.errors.tenantRequired", "Tenant context required") }, { status: 400 });
48
+ const page = query.page ?? 1;
49
+ const pageSize = Math.min(query.pageSize ?? 50, 100);
50
+ const em = ctx.container.resolve("em");
51
+ const qb = em.createQueryBuilder(WebhookDeliveryEntity, "d");
52
+ qb.where({ tenantId: auth.tenantId });
53
+ if (auth.orgId) {
54
+ qb.andWhere({ organizationId: auth.orgId });
55
+ }
56
+ if (query.webhookId) {
57
+ qb.andWhere({ webhookId: query.webhookId });
58
+ }
59
+ if (query.eventType) {
60
+ qb.andWhere({ eventType: query.eventType });
61
+ }
62
+ if (query.status) {
63
+ qb.andWhere({ status: query.status });
64
+ }
65
+ qb.orderBy({ createdAt: "desc" });
66
+ qb.limit(pageSize).offset((page - 1) * pageSize);
67
+ const [items, total] = await qb.getResultAndCount();
68
+ const payload = {
69
+ items: items.map((item) => ({
70
+ id: item.id,
71
+ webhookId: item.webhookId,
72
+ eventType: item.eventType,
73
+ messageId: item.messageId,
74
+ status: item.status,
75
+ responseStatus: item.responseStatus ?? null,
76
+ errorMessage: item.errorMessage ?? null,
77
+ attemptNumber: item.attemptNumber,
78
+ maxAttempts: item.maxAttempts,
79
+ targetUrl: item.targetUrl,
80
+ durationMs: item.durationMs ?? null,
81
+ enqueuedAt: item.enqueuedAt.toISOString(),
82
+ lastAttemptAt: item.lastAttemptAt?.toISOString() ?? null,
83
+ deliveredAt: item.deliveredAt?.toISOString() ?? null,
84
+ createdAt: item.createdAt.toISOString()
85
+ })),
86
+ total,
87
+ page,
88
+ pageSize,
89
+ totalPages: Math.ceil(total / pageSize)
90
+ };
91
+ throw json(payload);
92
+ }
93
+ }
94
+ });
95
+ const metadata = crud.metadata;
96
+ const GET = crud.GET;
97
+ const openApi = {
98
+ summary: "Webhook delivery logs",
99
+ description: "View delivery attempts for webhook endpoints.",
100
+ methods: {
101
+ GET: {
102
+ summary: "List delivery logs",
103
+ description: "Returns paginated webhook delivery attempts with filtering by webhook, event type, and status.",
104
+ query: webhookDeliveryQuerySchema,
105
+ responses: [{ status: 200, description: "Delivery log collection", schema: deliveryCollectionResponseSchema }],
106
+ errors: [
107
+ { status: 400, description: "Tenant context missing", schema: errorSchema },
108
+ { status: 401, description: "Unauthorized", schema: errorSchema }
109
+ ]
110
+ }
111
+ }
112
+ };
113
+ export {
114
+ GET,
115
+ metadata,
116
+ openApi
117
+ };
118
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/webhooks/api/webhook-deliveries/route.ts"],
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { WebhookDeliveryEntity } from '../../data/entities'\nimport { webhookDeliveryQuerySchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction json(payload: unknown, init: ResponseInit = { status: 200 }) {\n return new Response(JSON.stringify(payload), {\n ...init,\n headers: { 'content-type': 'application/json', ...(init.headers || {}) },\n })\n}\n\nconst deliveryItemSchema = z.object({\n id: z.string(),\n webhookId: z.string(),\n eventType: z.string(),\n messageId: z.string(),\n status: z.string(),\n responseStatus: z.number().nullable(),\n errorMessage: z.string().nullable(),\n attemptNumber: z.number(),\n maxAttempts: z.number(),\n targetUrl: z.string(),\n durationMs: z.number().nullable(),\n enqueuedAt: z.string(),\n lastAttemptAt: z.string().nullable(),\n deliveredAt: z.string().nullable(),\n createdAt: z.string(),\n})\n\nconst deliveryCollectionResponseSchema = z.object({\n items: z.array(deliveryItemSchema),\n total: z.number().int().nonnegative(),\n page: z.number().int().positive(),\n pageSize: z.number().int().positive(),\n totalPages: z.number().int().nonnegative(),\n})\n\nconst errorSchema = z.object({ error: z.string() })\n\nconst crud = makeCrudRoute<never, never, z.infer<typeof webhookDeliveryQuerySchema>>({\n metadata: {\n GET: { requireAuth: true, requireFeatures: ['webhooks.deliveries.view'] },\n },\n orm: { entity: WebhookDeliveryEntity, orgField: 'organizationId' },\n list: { schema: webhookDeliveryQuerySchema },\n hooks: {\n beforeList: async (query, ctx) => {\n const auth = ctx.auth\n const { translate } = await resolveTranslations()\n if (!auth?.tenantId) throw json({ error: translate('webhooks.errors.tenantRequired', 'Tenant context required') }, { status: 400 })\n\n const page = query.page ?? 1\n const pageSize = Math.min(query.pageSize ?? 50, 100)\n\n const em = ctx.container.resolve('em') as EntityManager\n const qb = em.createQueryBuilder(WebhookDeliveryEntity, 'd')\n qb.where({ tenantId: auth.tenantId })\n\n if (auth.orgId) {\n qb.andWhere({ organizationId: auth.orgId })\n }\n\n if (query.webhookId) {\n qb.andWhere({ webhookId: query.webhookId })\n }\n\n if (query.eventType) {\n qb.andWhere({ eventType: query.eventType })\n }\n\n if (query.status) {\n qb.andWhere({ status: query.status })\n }\n\n qb.orderBy({ createdAt: 'desc' })\n qb.limit(pageSize).offset((page - 1) * pageSize)\n const [items, total] = await qb.getResultAndCount()\n\n const payload = {\n items: items.map((item) => ({\n id: item.id,\n webhookId: item.webhookId,\n eventType: item.eventType,\n messageId: item.messageId,\n status: item.status,\n responseStatus: item.responseStatus ?? null,\n errorMessage: item.errorMessage ?? null,\n attemptNumber: item.attemptNumber,\n maxAttempts: item.maxAttempts,\n targetUrl: item.targetUrl,\n durationMs: item.durationMs ?? null,\n enqueuedAt: item.enqueuedAt.toISOString(),\n lastAttemptAt: item.lastAttemptAt?.toISOString() ?? null,\n deliveredAt: item.deliveredAt?.toISOString() ?? null,\n createdAt: item.createdAt.toISOString(),\n })),\n total,\n page,\n pageSize,\n totalPages: Math.ceil(total / pageSize),\n }\n\n throw json(payload)\n },\n },\n})\n\nexport const metadata = crud.metadata\nexport const GET = crud.GET\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Webhook delivery logs',\n description: 'View delivery attempts for webhook endpoints.',\n methods: {\n GET: {\n summary: 'List delivery logs',\n description: 'Returns paginated webhook delivery attempts with filtering by webhook, event type, and status.',\n query: webhookDeliveryQuerySchema,\n responses: [{ status: 200, description: 'Delivery log collection', schema: deliveryCollectionResponseSchema }],\n errors: [\n { status: 400, description: 'Tenant context missing', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAGlB,SAAS,qBAAqB;AAE9B,SAAS,6BAA6B;AACtC,SAAS,kCAAkC;AAC3C,SAAS,2BAA2B;AAEpC,SAAS,KAAK,SAAkB,OAAqB,EAAE,QAAQ,IAAI,GAAG;AACpE,SAAO,IAAI,SAAS,KAAK,UAAU,OAAO,GAAG;AAAA,IAC3C,GAAG;AAAA,IACH,SAAS,EAAE,gBAAgB,oBAAoB,GAAI,KAAK,WAAW,CAAC,EAAG;AAAA,EACzE,CAAC;AACH;AAEA,MAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,IAAI,EAAE,OAAO;AAAA,EACb,WAAW,EAAE,OAAO;AAAA,EACpB,WAAW,EAAE,OAAO;AAAA,EACpB,WAAW,EAAE,OAAO;AAAA,EACpB,QAAQ,EAAE,OAAO;AAAA,EACjB,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,eAAe,EAAE,OAAO;AAAA,EACxB,aAAa,EAAE,OAAO;AAAA,EACtB,WAAW,EAAE,OAAO;AAAA,EACpB,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,YAAY,EAAE,OAAO;AAAA,EACrB,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,WAAW,EAAE,OAAO;AACtB,CAAC;AAED,MAAM,mCAAmC,EAAE,OAAO;AAAA,EAChD,OAAO,EAAE,MAAM,kBAAkB;AAAA,EACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACpC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAChC,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACpC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC3C,CAAC;AAED,MAAM,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAElD,MAAM,OAAO,cAAwE;AAAA,EACnF,UAAU;AAAA,IACR,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,0BAA0B,EAAE;AAAA,EAC1E;AAAA,EACA,KAAK,EAAE,QAAQ,uBAAuB,UAAU,iBAAiB;AAAA,EACjE,MAAM,EAAE,QAAQ,2BAA2B;AAAA,EAC3C,OAAO;AAAA,IACL,YAAY,OAAO,OAAO,QAAQ;AAChC,YAAM,OAAO,IAAI;AACjB,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAI,CAAC,MAAM,SAAU,OAAM,KAAK,EAAE,OAAO,UAAU,kCAAkC,yBAAyB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAElI,YAAM,OAAO,MAAM,QAAQ;AAC3B,YAAM,WAAW,KAAK,IAAI,MAAM,YAAY,IAAI,GAAG;AAEnD,YAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,YAAM,KAAK,GAAG,mBAAmB,uBAAuB,GAAG;AAC3D,SAAG,MAAM,EAAE,UAAU,KAAK,SAAS,CAAC;AAEpC,UAAI,KAAK,OAAO;AACd,WAAG,SAAS,EAAE,gBAAgB,KAAK,MAAM,CAAC;AAAA,MAC5C;AAEA,UAAI,MAAM,WAAW;AACnB,WAAG,SAAS,EAAE,WAAW,MAAM,UAAU,CAAC;AAAA,MAC5C;AAEA,UAAI,MAAM,WAAW;AACnB,WAAG,SAAS,EAAE,WAAW,MAAM,UAAU,CAAC;AAAA,MAC5C;AAEA,UAAI,MAAM,QAAQ;AAChB,WAAG,SAAS,EAAE,QAAQ,MAAM,OAAO,CAAC;AAAA,MACtC;AAEA,SAAG,QAAQ,EAAE,WAAW,OAAO,CAAC;AAChC,SAAG,MAAM,QAAQ,EAAE,QAAQ,OAAO,KAAK,QAAQ;AAC/C,YAAM,CAAC,OAAO,KAAK,IAAI,MAAM,GAAG,kBAAkB;AAElD,YAAM,UAAU;AAAA,QACd,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,UAC1B,IAAI,KAAK;AAAA,UACT,WAAW,KAAK;AAAA,UAChB,WAAW,KAAK;AAAA,UAChB,WAAW,KAAK;AAAA,UAChB,QAAQ,KAAK;AAAA,UACb,gBAAgB,KAAK,kBAAkB;AAAA,UACvC,cAAc,KAAK,gBAAgB;AAAA,UACnC,eAAe,KAAK;AAAA,UACpB,aAAa,KAAK;AAAA,UAClB,WAAW,KAAK;AAAA,UAChB,YAAY,KAAK,cAAc;AAAA,UAC/B,YAAY,KAAK,WAAW,YAAY;AAAA,UACxC,eAAe,KAAK,eAAe,YAAY,KAAK;AAAA,UACpD,aAAa,KAAK,aAAa,YAAY,KAAK;AAAA,UAChD,WAAW,KAAK,UAAU,YAAY;AAAA,QACxC,EAAE;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,KAAK,KAAK,QAAQ,QAAQ;AAAA,MACxC;AAEA,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,EACF;AACF,CAAC;AAEM,MAAM,WAAW,KAAK;AACtB,MAAM,MAAM,KAAK;AAEjB,MAAM,UAA2B;AAAA,EACtC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,OAAO;AAAA,MACP,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,2BAA2B,QAAQ,iCAAiC,CAAC;AAAA,MAC7G,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,0BAA0B,QAAQ,YAAY;AAAA,QAC1E,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,YAAY;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,268 @@
1
+ import { z } from "zod";
2
+ import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
+ import { WebhookEntity } from "../../data/entities.js";
4
+ import { webhookCreateSchema, webhookUpdateSchema, webhookListQuerySchema } from "../../data/validators.js";
5
+ import { generateWebhookSecret } from "@open-mercato/shared/lib/webhooks";
6
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
7
+ import { escapeLikePattern } from "@open-mercato/shared/lib/db/escapeLikePattern";
8
+ import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
9
+ function json(payload, init = { status: 200 }) {
10
+ return new Response(JSON.stringify(payload), {
11
+ ...init,
12
+ headers: { "content-type": "application/json", ...init.headers || {} }
13
+ });
14
+ }
15
+ const webhookListItemSchema = z.object({
16
+ id: z.string(),
17
+ name: z.string(),
18
+ description: z.string().nullable(),
19
+ url: z.string(),
20
+ subscribedEvents: z.array(z.string()),
21
+ httpMethod: z.string(),
22
+ isActive: z.boolean(),
23
+ deliveryStrategy: z.string(),
24
+ maxRetries: z.number(),
25
+ consecutiveFailures: z.number(),
26
+ lastSuccessAt: z.string().nullable(),
27
+ lastFailureAt: z.string().nullable(),
28
+ createdAt: z.string(),
29
+ updatedAt: z.string()
30
+ });
31
+ const webhookCollectionResponseSchema = z.object({
32
+ items: z.array(webhookListItemSchema),
33
+ total: z.number().int().nonnegative(),
34
+ page: z.number().int().positive(),
35
+ pageSize: z.number().int().positive(),
36
+ totalPages: z.number().int().nonnegative()
37
+ });
38
+ const webhookCreateResponseSchema = z.object({
39
+ id: z.string(),
40
+ name: z.string(),
41
+ url: z.string(),
42
+ secret: z.string(),
43
+ subscribedEvents: z.array(z.string()),
44
+ isActive: z.boolean()
45
+ });
46
+ const webhookDetailResponseSchema = webhookListItemSchema.extend({
47
+ customHeaders: z.record(z.string(), z.string()).nullable(),
48
+ strategyConfig: z.record(z.string(), z.unknown()).nullable(),
49
+ timeoutMs: z.number(),
50
+ rateLimitPerMinute: z.number(),
51
+ autoDisableThreshold: z.number(),
52
+ integrationId: z.string().nullable()
53
+ });
54
+ const deleteResponseSchema = z.object({ success: z.literal(true) });
55
+ const errorSchema = z.object({ error: z.string() });
56
+ const crud = makeCrudRoute({
57
+ metadata: {
58
+ GET: { requireAuth: true, requireFeatures: ["webhooks.view"] },
59
+ POST: { requireAuth: true, requireFeatures: ["webhooks.create"] },
60
+ PUT: { requireAuth: true, requireFeatures: ["webhooks.edit"] },
61
+ DELETE: { requireAuth: true, requireFeatures: ["webhooks.delete"] }
62
+ },
63
+ orm: { entity: WebhookEntity, orgField: "organizationId" },
64
+ list: { schema: webhookListQuerySchema },
65
+ create: {
66
+ schema: webhookCreateSchema,
67
+ mapToEntity: (input, ctx) => {
68
+ const scopedCtx = ctx;
69
+ const secret = scopedCtx.__webhookSecret;
70
+ if (!secret) throw new Error("Webhook secret not prepared");
71
+ return {
72
+ name: input.name,
73
+ description: input.description ?? null,
74
+ url: input.url,
75
+ secret,
76
+ subscribedEvents: input.subscribedEvents,
77
+ httpMethod: input.httpMethod ?? "POST",
78
+ customHeaders: input.customHeaders ?? null,
79
+ deliveryStrategy: input.deliveryStrategy ?? "http",
80
+ strategyConfig: input.strategyConfig ?? null,
81
+ maxRetries: input.maxRetries ?? 10,
82
+ timeoutMs: input.timeoutMs ?? 15e3,
83
+ rateLimitPerMinute: input.rateLimitPerMinute ?? 0,
84
+ autoDisableThreshold: input.autoDisableThreshold ?? 100,
85
+ integrationId: input.integrationId ?? null,
86
+ organizationId: ctx.auth?.orgId ?? "",
87
+ tenantId: ctx.auth?.tenantId ?? ""
88
+ };
89
+ },
90
+ response: (entity) => ({
91
+ id: entity.id,
92
+ name: entity.name,
93
+ url: entity.url,
94
+ secret: entity.__revealSecret ?? "***",
95
+ subscribedEvents: entity.subscribedEvents,
96
+ isActive: entity.isActive
97
+ })
98
+ },
99
+ update: {
100
+ schema: webhookUpdateSchema,
101
+ applyToEntity: (entity, input) => {
102
+ if (input.name !== void 0) entity.name = input.name;
103
+ if (input.description !== void 0) entity.description = input.description;
104
+ if (input.url !== void 0) entity.url = input.url;
105
+ if (input.subscribedEvents !== void 0) entity.subscribedEvents = input.subscribedEvents;
106
+ if (input.httpMethod !== void 0) entity.httpMethod = input.httpMethod;
107
+ if (input.customHeaders !== void 0) entity.customHeaders = input.customHeaders;
108
+ if (input.deliveryStrategy !== void 0) entity.deliveryStrategy = input.deliveryStrategy;
109
+ if (input.strategyConfig !== void 0) entity.strategyConfig = input.strategyConfig;
110
+ if (input.maxRetries !== void 0) entity.maxRetries = input.maxRetries;
111
+ if (input.timeoutMs !== void 0) entity.timeoutMs = input.timeoutMs;
112
+ if (input.rateLimitPerMinute !== void 0) entity.rateLimitPerMinute = input.rateLimitPerMinute;
113
+ if (input.autoDisableThreshold !== void 0) entity.autoDisableThreshold = input.autoDisableThreshold;
114
+ if (input.integrationId !== void 0) entity.integrationId = input.integrationId;
115
+ if (input.isActive !== void 0) entity.isActive = input.isActive;
116
+ }
117
+ },
118
+ del: { idFrom: "query" },
119
+ hooks: {
120
+ beforeList: async (query, ctx) => {
121
+ const auth = ctx.auth;
122
+ const { translate } = await resolveTranslations();
123
+ if (!auth?.tenantId) throw json({ error: translate("webhooks.errors.tenantRequired", "Tenant context required") }, { status: 400 });
124
+ const page = Math.max(parseInt(query.page ?? "1", 10) || 1, 1);
125
+ const pageSize = Math.min(Math.max(parseInt(query.pageSize ?? "20", 10) || 20, 1), 100);
126
+ const search = (query.search ?? "").trim().toLowerCase();
127
+ const organizationIds = Array.isArray(ctx.organizationIds) ? ctx.organizationIds : null;
128
+ if (organizationIds && organizationIds.length === 0) {
129
+ throw json({ items: [], total: 0, page, pageSize, totalPages: 0 });
130
+ }
131
+ const em = ctx.container.resolve("em");
132
+ const qb = em.createQueryBuilder(WebhookEntity, "w");
133
+ qb.where({ deletedAt: null });
134
+ qb.andWhere({ tenantId: auth.tenantId });
135
+ if (organizationIds && organizationIds.length > 0) {
136
+ qb.andWhere({ organizationId: { $in: organizationIds } });
137
+ } else if (auth.orgId) {
138
+ qb.andWhere({ organizationId: auth.orgId });
139
+ }
140
+ if (search) {
141
+ const pattern = `%${escapeLikePattern(search)}%`;
142
+ qb.andWhere({ name: { $ilike: pattern } });
143
+ }
144
+ if (query.isActive !== void 0 && query.isActive !== "") {
145
+ const active = parseBooleanToken(query.isActive);
146
+ if (active !== null) {
147
+ qb.andWhere({ isActive: active });
148
+ }
149
+ }
150
+ qb.orderBy({ createdAt: "desc" });
151
+ qb.limit(pageSize).offset((page - 1) * pageSize);
152
+ const [items, total] = await qb.getResultAndCount();
153
+ const payload = {
154
+ items: items.map((item) => ({
155
+ id: item.id,
156
+ name: item.name,
157
+ description: item.description ?? null,
158
+ url: item.url,
159
+ subscribedEvents: item.subscribedEvents,
160
+ httpMethod: item.httpMethod,
161
+ isActive: item.isActive,
162
+ deliveryStrategy: item.deliveryStrategy,
163
+ maxRetries: item.maxRetries,
164
+ consecutiveFailures: item.consecutiveFailures,
165
+ lastSuccessAt: item.lastSuccessAt?.toISOString() ?? null,
166
+ lastFailureAt: item.lastFailureAt?.toISOString() ?? null,
167
+ createdAt: item.createdAt.toISOString(),
168
+ updatedAt: item.updatedAt.toISOString()
169
+ })),
170
+ total,
171
+ page,
172
+ pageSize,
173
+ totalPages: Math.ceil(total / pageSize)
174
+ };
175
+ throw json(payload);
176
+ },
177
+ beforeCreate: async (input, ctx) => {
178
+ const auth = ctx.auth;
179
+ const { translate } = await resolveTranslations();
180
+ if (!auth?.tenantId) throw json({ error: translate("webhooks.errors.tenantRequired", "Tenant context required") }, { status: 400 });
181
+ if (!auth?.orgId) throw json({ error: translate("webhooks.errors.orgRequired", "Organization context required") }, { status: 400 });
182
+ const scopedCtx = ctx;
183
+ scopedCtx.__webhookSecret = generateWebhookSecret();
184
+ return input;
185
+ },
186
+ afterCreate: async (entity, ctx) => {
187
+ const scopedCtx = ctx;
188
+ if (scopedCtx.__webhookSecret) {
189
+ ;
190
+ entity.__revealSecret = scopedCtx.__webhookSecret;
191
+ }
192
+ },
193
+ beforeDelete: async (id, ctx) => {
194
+ const auth = ctx.auth;
195
+ const { translate } = await resolveTranslations();
196
+ if (!auth?.tenantId) throw json({ error: translate("webhooks.errors.tenantRequired", "Tenant context required") }, { status: 400 });
197
+ const em = ctx.container.resolve("em");
198
+ const record = await em.findOne(WebhookEntity, { id, deletedAt: null, tenantId: auth.tenantId });
199
+ if (!record) throw json({ error: translate("webhooks.errors.notFound", "Webhook not found") }, { status: 404 });
200
+ const allowedIds = ctx.organizationScope?.allowedIds ?? null;
201
+ if (record.organizationId && Array.isArray(allowedIds) && allowedIds.length > 0) {
202
+ if (!allowedIds.includes(record.organizationId)) {
203
+ throw json({ error: translate("webhooks.errors.forbidden", "Forbidden") }, { status: 403 });
204
+ }
205
+ }
206
+ }
207
+ }
208
+ });
209
+ const metadata = crud.metadata;
210
+ const GET = crud.GET;
211
+ const POST = crud.POST;
212
+ const PUT = crud.PUT;
213
+ const DELETE = crud.DELETE;
214
+ const openApi = {
215
+ summary: "Manage webhooks",
216
+ description: "CRUD operations for webhook endpoints following the Standard Webhooks specification.",
217
+ methods: {
218
+ GET: {
219
+ summary: "List webhooks",
220
+ description: "Returns paginated webhooks for the current tenant and organization.",
221
+ query: webhookListQuerySchema,
222
+ responses: [{ status: 200, description: "Webhook collection", schema: webhookCollectionResponseSchema }],
223
+ errors: [
224
+ { status: 400, description: "Tenant context missing", schema: errorSchema },
225
+ { status: 401, description: "Unauthorized", schema: errorSchema }
226
+ ]
227
+ },
228
+ POST: {
229
+ summary: "Create webhook",
230
+ description: "Creates a new webhook endpoint. A signing secret (whsec_ prefixed) is auto-generated and returned once.",
231
+ requestBody: { contentType: "application/json", schema: webhookCreateSchema, description: "Webhook configuration." },
232
+ responses: [{ status: 201, description: "Webhook created", schema: webhookCreateResponseSchema }],
233
+ errors: [
234
+ { status: 400, description: "Invalid payload", schema: errorSchema },
235
+ { status: 401, description: "Unauthorized", schema: errorSchema }
236
+ ]
237
+ },
238
+ PUT: {
239
+ summary: "Update webhook",
240
+ description: "Updates an existing webhook configuration.",
241
+ requestBody: { contentType: "application/json", schema: webhookUpdateSchema, description: "Fields to update." },
242
+ responses: [{ status: 200, description: "Webhook updated", schema: webhookDetailResponseSchema }],
243
+ errors: [
244
+ { status: 400, description: "Invalid payload", schema: errorSchema },
245
+ { status: 404, description: "Not found", schema: errorSchema }
246
+ ]
247
+ },
248
+ DELETE: {
249
+ summary: "Delete webhook",
250
+ description: "Soft-deletes a webhook endpoint.",
251
+ query: z.object({ id: z.string().uuid().describe("Webhook ID to delete") }),
252
+ responses: [{ status: 200, description: "Deleted", schema: deleteResponseSchema }],
253
+ errors: [
254
+ { status: 404, description: "Not found", schema: errorSchema },
255
+ { status: 403, description: "Forbidden", schema: errorSchema }
256
+ ]
257
+ }
258
+ }
259
+ };
260
+ export {
261
+ DELETE,
262
+ GET,
263
+ POST,
264
+ PUT,
265
+ metadata,
266
+ openApi
267
+ };
268
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/webhooks/api/webhooks/route.ts"],
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { WebhookEntity } from '../../data/entities'\nimport { webhookCreateSchema, webhookUpdateSchema, webhookListQuerySchema } from '../../data/validators'\nimport { generateWebhookSecret } from '@open-mercato/shared/lib/webhooks'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport type { WebhookCreateInput, WebhookUpdateInput } from '../../data/validators'\n\ntype WebhookCrudCtx = CrudCtx & {\n __webhookSecret?: string\n}\n\nfunction json(payload: unknown, init: ResponseInit = { status: 200 }) {\n return new Response(JSON.stringify(payload), {\n ...init,\n headers: { 'content-type': 'application/json', ...(init.headers || {}) },\n })\n}\n\nconst webhookListItemSchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().nullable(),\n url: z.string(),\n subscribedEvents: z.array(z.string()),\n httpMethod: z.string(),\n isActive: z.boolean(),\n deliveryStrategy: z.string(),\n maxRetries: z.number(),\n consecutiveFailures: z.number(),\n lastSuccessAt: z.string().nullable(),\n lastFailureAt: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string(),\n})\n\nconst webhookCollectionResponseSchema = z.object({\n items: z.array(webhookListItemSchema),\n total: z.number().int().nonnegative(),\n page: z.number().int().positive(),\n pageSize: z.number().int().positive(),\n totalPages: z.number().int().nonnegative(),\n})\n\nconst webhookCreateResponseSchema = z.object({\n id: z.string(),\n name: z.string(),\n url: z.string(),\n secret: z.string(),\n subscribedEvents: z.array(z.string()),\n isActive: z.boolean(),\n})\n\nconst webhookDetailResponseSchema = webhookListItemSchema.extend({\n customHeaders: z.record(z.string(), z.string()).nullable(),\n strategyConfig: z.record(z.string(), z.unknown()).nullable(),\n timeoutMs: z.number(),\n rateLimitPerMinute: z.number(),\n autoDisableThreshold: z.number(),\n integrationId: z.string().nullable(),\n})\n\nconst deleteResponseSchema = z.object({ success: z.literal(true) })\nconst errorSchema = z.object({ error: z.string() })\n\nconst crud = makeCrudRoute<WebhookCreateInput, WebhookUpdateInput, z.infer<typeof webhookListQuerySchema>>({\n metadata: {\n GET: { requireAuth: true, requireFeatures: ['webhooks.view'] },\n POST: { requireAuth: true, requireFeatures: ['webhooks.create'] },\n PUT: { requireAuth: true, requireFeatures: ['webhooks.edit'] },\n DELETE: { requireAuth: true, requireFeatures: ['webhooks.delete'] },\n },\n orm: { entity: WebhookEntity, orgField: 'organizationId' },\n list: { schema: webhookListQuerySchema },\n create: {\n schema: webhookCreateSchema,\n mapToEntity: (input, ctx) => {\n const scopedCtx = ctx as WebhookCrudCtx\n const secret = scopedCtx.__webhookSecret\n if (!secret) throw new Error('Webhook secret not prepared')\n return {\n name: input.name,\n description: input.description ?? null,\n url: input.url,\n secret,\n subscribedEvents: input.subscribedEvents,\n httpMethod: input.httpMethod ?? 'POST',\n customHeaders: input.customHeaders ?? null,\n deliveryStrategy: input.deliveryStrategy ?? 'http',\n strategyConfig: input.strategyConfig ?? null,\n maxRetries: input.maxRetries ?? 10,\n timeoutMs: input.timeoutMs ?? 15000,\n rateLimitPerMinute: input.rateLimitPerMinute ?? 0,\n autoDisableThreshold: input.autoDisableThreshold ?? 100,\n integrationId: input.integrationId ?? null,\n organizationId: ctx.auth?.orgId ?? '',\n tenantId: ctx.auth?.tenantId ?? '',\n }\n },\n response: (entity) => ({\n id: entity.id,\n name: entity.name,\n url: entity.url,\n secret: (entity as WebhookEntity & { __revealSecret?: string }).__revealSecret ?? '***',\n subscribedEvents: entity.subscribedEvents,\n isActive: entity.isActive,\n }),\n },\n update: {\n schema: webhookUpdateSchema,\n applyToEntity: (entity, input) => {\n if (input.name !== undefined) entity.name = input.name\n if (input.description !== undefined) entity.description = input.description\n if (input.url !== undefined) entity.url = input.url\n if (input.subscribedEvents !== undefined) entity.subscribedEvents = input.subscribedEvents\n if (input.httpMethod !== undefined) entity.httpMethod = input.httpMethod\n if (input.customHeaders !== undefined) entity.customHeaders = input.customHeaders\n if (input.deliveryStrategy !== undefined) entity.deliveryStrategy = input.deliveryStrategy\n if (input.strategyConfig !== undefined) entity.strategyConfig = input.strategyConfig\n if (input.maxRetries !== undefined) entity.maxRetries = input.maxRetries\n if (input.timeoutMs !== undefined) entity.timeoutMs = input.timeoutMs\n if (input.rateLimitPerMinute !== undefined) entity.rateLimitPerMinute = input.rateLimitPerMinute\n if (input.autoDisableThreshold !== undefined) entity.autoDisableThreshold = input.autoDisableThreshold\n if (input.integrationId !== undefined) entity.integrationId = input.integrationId\n if (input.isActive !== undefined) entity.isActive = input.isActive\n },\n },\n del: { idFrom: 'query' },\n hooks: {\n beforeList: async (query, ctx) => {\n const auth = ctx.auth\n const { translate } = await resolveTranslations()\n if (!auth?.tenantId) throw json({ error: translate('webhooks.errors.tenantRequired', 'Tenant context required') }, { status: 400 })\n\n const page = Math.max(parseInt(query.page ?? '1', 10) || 1, 1)\n const pageSize = Math.min(Math.max(parseInt(query.pageSize ?? '20', 10) || 20, 1), 100)\n const search = (query.search ?? '').trim().toLowerCase()\n\n const organizationIds = Array.isArray(ctx.organizationIds) ? ctx.organizationIds : null\n if (organizationIds && organizationIds.length === 0) {\n throw json({ items: [], total: 0, page, pageSize, totalPages: 0 })\n }\n\n const em = ctx.container.resolve('em') as EntityManager\n const qb = em.createQueryBuilder(WebhookEntity, 'w')\n qb.where({ deletedAt: null })\n qb.andWhere({ tenantId: auth.tenantId })\n\n if (organizationIds && organizationIds.length > 0) {\n qb.andWhere({ organizationId: { $in: organizationIds } })\n } else if (auth.orgId) {\n qb.andWhere({ organizationId: auth.orgId })\n }\n\n if (search) {\n const pattern = `%${escapeLikePattern(search)}%`\n qb.andWhere({ name: { $ilike: pattern } })\n }\n\n if (query.isActive !== undefined && query.isActive !== '') {\n const active = parseBooleanToken(query.isActive)\n if (active !== null) {\n qb.andWhere({ isActive: active })\n }\n }\n\n qb.orderBy({ createdAt: 'desc' })\n qb.limit(pageSize).offset((page - 1) * pageSize)\n const [items, total] = await qb.getResultAndCount()\n\n const payload = {\n items: items.map((item) => ({\n id: item.id,\n name: item.name,\n description: item.description ?? null,\n url: item.url,\n subscribedEvents: item.subscribedEvents,\n httpMethod: item.httpMethod,\n isActive: item.isActive,\n deliveryStrategy: item.deliveryStrategy,\n maxRetries: item.maxRetries,\n consecutiveFailures: item.consecutiveFailures,\n lastSuccessAt: item.lastSuccessAt?.toISOString() ?? null,\n lastFailureAt: item.lastFailureAt?.toISOString() ?? null,\n createdAt: item.createdAt.toISOString(),\n updatedAt: item.updatedAt.toISOString(),\n })),\n total,\n page,\n pageSize,\n totalPages: Math.ceil(total / pageSize),\n }\n\n throw json(payload)\n },\n beforeCreate: async (input, ctx) => {\n const auth = ctx.auth\n const { translate } = await resolveTranslations()\n if (!auth?.tenantId) throw json({ error: translate('webhooks.errors.tenantRequired', 'Tenant context required') }, { status: 400 })\n if (!auth?.orgId) throw json({ error: translate('webhooks.errors.orgRequired', 'Organization context required') }, { status: 400 })\n\n const scopedCtx = ctx as WebhookCrudCtx\n scopedCtx.__webhookSecret = generateWebhookSecret()\n\n return input\n },\n afterCreate: async (entity, ctx) => {\n const scopedCtx = ctx as WebhookCrudCtx\n if (scopedCtx.__webhookSecret) {\n ;(entity as WebhookEntity & { __revealSecret?: string }).__revealSecret = scopedCtx.__webhookSecret\n }\n },\n beforeDelete: async (id, ctx) => {\n const auth = ctx.auth\n const { translate } = await resolveTranslations()\n if (!auth?.tenantId) throw json({ error: translate('webhooks.errors.tenantRequired', 'Tenant context required') }, { status: 400 })\n\n const em = ctx.container.resolve('em') as EntityManager\n const record = await em.findOne(WebhookEntity, { id, deletedAt: null, tenantId: auth.tenantId })\n if (!record) throw json({ error: translate('webhooks.errors.notFound', 'Webhook not found') }, { status: 404 })\n\n const allowedIds = ctx.organizationScope?.allowedIds ?? null\n if (record.organizationId && Array.isArray(allowedIds) && allowedIds.length > 0) {\n if (!allowedIds.includes(record.organizationId)) {\n throw json({ error: translate('webhooks.errors.forbidden', 'Forbidden') }, { status: 403 })\n }\n }\n },\n },\n})\n\nexport const metadata = crud.metadata\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Manage webhooks',\n description: 'CRUD operations for webhook endpoints following the Standard Webhooks specification.',\n methods: {\n GET: {\n summary: 'List webhooks',\n description: 'Returns paginated webhooks for the current tenant and organization.',\n query: webhookListQuerySchema,\n responses: [{ status: 200, description: 'Webhook collection', schema: webhookCollectionResponseSchema }],\n errors: [\n { status: 400, description: 'Tenant context missing', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n POST: {\n summary: 'Create webhook',\n description: 'Creates a new webhook endpoint. A signing secret (whsec_ prefixed) is auto-generated and returned once.',\n requestBody: { contentType: 'application/json', schema: webhookCreateSchema, description: 'Webhook configuration.' },\n responses: [{ status: 201, description: 'Webhook created', schema: webhookCreateResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid payload', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n PUT: {\n summary: 'Update webhook',\n description: 'Updates an existing webhook configuration.',\n requestBody: { contentType: 'application/json', schema: webhookUpdateSchema, description: 'Fields to update.' },\n responses: [{ status: 200, description: 'Webhook updated', schema: webhookDetailResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid payload', schema: errorSchema },\n { status: 404, description: 'Not found', schema: errorSchema },\n ],\n },\n DELETE: {\n summary: 'Delete webhook',\n description: 'Soft-deletes a webhook endpoint.',\n query: z.object({ id: z.string().uuid().describe('Webhook ID to delete') }),\n responses: [{ status: 200, description: 'Deleted', schema: deleteResponseSchema }],\n errors: [\n { status: 404, description: 'Not found', schema: errorSchema },\n { status: 403, description: 'Forbidden', schema: errorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAGlB,SAAS,qBAAqB;AAE9B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB,qBAAqB,8BAA8B;AACjF,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAOlC,SAAS,KAAK,SAAkB,OAAqB,EAAE,QAAQ,IAAI,GAAG;AACpE,SAAO,IAAI,SAAS,KAAK,UAAU,OAAO,GAAG;AAAA,IAC3C,GAAG;AAAA,IACH,SAAS,EAAE,gBAAgB,oBAAoB,GAAI,KAAK,WAAW,CAAC,EAAG;AAAA,EACzE,CAAC;AACH;AAEA,MAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,IAAI,EAAE,OAAO;AAAA,EACb,MAAM,EAAE,OAAO;AAAA,EACf,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,KAAK,EAAE,OAAO;AAAA,EACd,kBAAkB,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EACpC,YAAY,EAAE,OAAO;AAAA,EACrB,UAAU,EAAE,QAAQ;AAAA,EACpB,kBAAkB,EAAE,OAAO;AAAA,EAC3B,YAAY,EAAE,OAAO;AAAA,EACrB,qBAAqB,EAAE,OAAO;AAAA,EAC9B,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,WAAW,EAAE,OAAO;AAAA,EACpB,WAAW,EAAE,OAAO;AACtB,CAAC;AAED,MAAM,kCAAkC,EAAE,OAAO;AAAA,EAC/C,OAAO,EAAE,MAAM,qBAAqB;AAAA,EACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACpC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAChC,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACpC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC3C,CAAC;AAED,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAC3C,IAAI,EAAE,OAAO;AAAA,EACb,MAAM,EAAE,OAAO;AAAA,EACf,KAAK,EAAE,OAAO;AAAA,EACd,QAAQ,EAAE,OAAO;AAAA,EACjB,kBAAkB,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EACpC,UAAU,EAAE,QAAQ;AACtB,CAAC;AAED,MAAM,8BAA8B,sBAAsB,OAAO;AAAA,EAC/D,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACzD,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EAC3D,WAAW,EAAE,OAAO;AAAA,EACpB,oBAAoB,EAAE,OAAO;AAAA,EAC7B,sBAAsB,EAAE,OAAO;AAAA,EAC/B,eAAe,EAAE,OAAO,EAAE,SAAS;AACrC,CAAC;AAED,MAAM,uBAAuB,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI,EAAE,CAAC;AAClE,MAAM,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAElD,MAAM,OAAO,cAA8F;AAAA,EACzG,UAAU;AAAA,IACR,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,eAAe,EAAE;AAAA,IAC7D,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,iBAAiB,EAAE;AAAA,IAChE,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,eAAe,EAAE;AAAA,IAC7D,QAAQ,EAAE,aAAa,MAAM,iBAAiB,CAAC,iBAAiB,EAAE;AAAA,EACpE;AAAA,EACA,KAAK,EAAE,QAAQ,eAAe,UAAU,iBAAiB;AAAA,EACzD,MAAM,EAAE,QAAQ,uBAAuB;AAAA,EACvC,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,aAAa,CAAC,OAAO,QAAQ;AAC3B,YAAM,YAAY;AAClB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,6BAA6B;AAC1D,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,aAAa,MAAM,eAAe;AAAA,QAClC,KAAK,MAAM;AAAA,QACX;AAAA,QACA,kBAAkB,MAAM;AAAA,QACxB,YAAY,MAAM,cAAc;AAAA,QAChC,eAAe,MAAM,iBAAiB;AAAA,QACtC,kBAAkB,MAAM,oBAAoB;AAAA,QAC5C,gBAAgB,MAAM,kBAAkB;AAAA,QACxC,YAAY,MAAM,cAAc;AAAA,QAChC,WAAW,MAAM,aAAa;AAAA,QAC9B,oBAAoB,MAAM,sBAAsB;AAAA,QAChD,sBAAsB,MAAM,wBAAwB;AAAA,QACpD,eAAe,MAAM,iBAAiB;AAAA,QACtC,gBAAgB,IAAI,MAAM,SAAS;AAAA,QACnC,UAAU,IAAI,MAAM,YAAY;AAAA,MAClC;AAAA,IACF;AAAA,IACA,UAAU,CAAC,YAAY;AAAA,MACrB,IAAI,OAAO;AAAA,MACX,MAAM,OAAO;AAAA,MACb,KAAK,OAAO;AAAA,MACZ,QAAS,OAAuD,kBAAkB;AAAA,MAClF,kBAAkB,OAAO;AAAA,MACzB,UAAU,OAAO;AAAA,IACnB;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,eAAe,CAAC,QAAQ,UAAU;AAChC,UAAI,MAAM,SAAS,OAAW,QAAO,OAAO,MAAM;AAClD,UAAI,MAAM,gBAAgB,OAAW,QAAO,cAAc,MAAM;AAChE,UAAI,MAAM,QAAQ,OAAW,QAAO,MAAM,MAAM;AAChD,UAAI,MAAM,qBAAqB,OAAW,QAAO,mBAAmB,MAAM;AAC1E,UAAI,MAAM,eAAe,OAAW,QAAO,aAAa,MAAM;AAC9D,UAAI,MAAM,kBAAkB,OAAW,QAAO,gBAAgB,MAAM;AACpE,UAAI,MAAM,qBAAqB,OAAW,QAAO,mBAAmB,MAAM;AAC1E,UAAI,MAAM,mBAAmB,OAAW,QAAO,iBAAiB,MAAM;AACtE,UAAI,MAAM,eAAe,OAAW,QAAO,aAAa,MAAM;AAC9D,UAAI,MAAM,cAAc,OAAW,QAAO,YAAY,MAAM;AAC5D,UAAI,MAAM,uBAAuB,OAAW,QAAO,qBAAqB,MAAM;AAC9E,UAAI,MAAM,yBAAyB,OAAW,QAAO,uBAAuB,MAAM;AAClF,UAAI,MAAM,kBAAkB,OAAW,QAAO,gBAAgB,MAAM;AACpE,UAAI,MAAM,aAAa,OAAW,QAAO,WAAW,MAAM;AAAA,IAC5D;AAAA,EACF;AAAA,EACA,KAAK,EAAE,QAAQ,QAAQ;AAAA,EACvB,OAAO;AAAA,IACL,YAAY,OAAO,OAAO,QAAQ;AAChC,YAAM,OAAO,IAAI;AACjB,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAI,CAAC,MAAM,SAAU,OAAM,KAAK,EAAE,OAAO,UAAU,kCAAkC,yBAAyB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAElI,YAAM,OAAO,KAAK,IAAI,SAAS,MAAM,QAAQ,KAAK,EAAE,KAAK,GAAG,CAAC;AAC7D,YAAM,WAAW,KAAK,IAAI,KAAK,IAAI,SAAS,MAAM,YAAY,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,GAAG;AACtF,YAAM,UAAU,MAAM,UAAU,IAAI,KAAK,EAAE,YAAY;AAEvD,YAAM,kBAAkB,MAAM,QAAQ,IAAI,eAAe,IAAI,IAAI,kBAAkB;AACnF,UAAI,mBAAmB,gBAAgB,WAAW,GAAG;AACnD,cAAM,KAAK,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,MAAM,UAAU,YAAY,EAAE,CAAC;AAAA,MACnE;AAEA,YAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,YAAM,KAAK,GAAG,mBAAmB,eAAe,GAAG;AACnD,SAAG,MAAM,EAAE,WAAW,KAAK,CAAC;AAC5B,SAAG,SAAS,EAAE,UAAU,KAAK,SAAS,CAAC;AAEvC,UAAI,mBAAmB,gBAAgB,SAAS,GAAG;AACjD,WAAG,SAAS,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,CAAC;AAAA,MAC1D,WAAW,KAAK,OAAO;AACrB,WAAG,SAAS,EAAE,gBAAgB,KAAK,MAAM,CAAC;AAAA,MAC5C;AAEA,UAAI,QAAQ;AACV,cAAM,UAAU,IAAI,kBAAkB,MAAM,CAAC;AAC7C,WAAG,SAAS,EAAE,MAAM,EAAE,QAAQ,QAAQ,EAAE,CAAC;AAAA,MAC3C;AAEA,UAAI,MAAM,aAAa,UAAa,MAAM,aAAa,IAAI;AACzD,cAAM,SAAS,kBAAkB,MAAM,QAAQ;AAC/C,YAAI,WAAW,MAAM;AACnB,aAAG,SAAS,EAAE,UAAU,OAAO,CAAC;AAAA,QAClC;AAAA,MACF;AAEA,SAAG,QAAQ,EAAE,WAAW,OAAO,CAAC;AAChC,SAAG,MAAM,QAAQ,EAAE,QAAQ,OAAO,KAAK,QAAQ;AAC/C,YAAM,CAAC,OAAO,KAAK,IAAI,MAAM,GAAG,kBAAkB;AAElD,YAAM,UAAU;AAAA,QACd,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,UAC1B,IAAI,KAAK;AAAA,UACT,MAAM,KAAK;AAAA,UACX,aAAa,KAAK,eAAe;AAAA,UACjC,KAAK,KAAK;AAAA,UACV,kBAAkB,KAAK;AAAA,UACvB,YAAY,KAAK;AAAA,UACjB,UAAU,KAAK;AAAA,UACf,kBAAkB,KAAK;AAAA,UACvB,YAAY,KAAK;AAAA,UACjB,qBAAqB,KAAK;AAAA,UAC1B,eAAe,KAAK,eAAe,YAAY,KAAK;AAAA,UACpD,eAAe,KAAK,eAAe,YAAY,KAAK;AAAA,UACpD,WAAW,KAAK,UAAU,YAAY;AAAA,UACtC,WAAW,KAAK,UAAU,YAAY;AAAA,QACxC,EAAE;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,KAAK,KAAK,QAAQ,QAAQ;AAAA,MACxC;AAEA,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,IACA,cAAc,OAAO,OAAO,QAAQ;AAClC,YAAM,OAAO,IAAI;AACjB,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAI,CAAC,MAAM,SAAU,OAAM,KAAK,EAAE,OAAO,UAAU,kCAAkC,yBAAyB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAClI,UAAI,CAAC,MAAM,MAAO,OAAM,KAAK,EAAE,OAAO,UAAU,+BAA+B,+BAA+B,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAElI,YAAM,YAAY;AAClB,gBAAU,kBAAkB,sBAAsB;AAElD,aAAO;AAAA,IACT;AAAA,IACA,aAAa,OAAO,QAAQ,QAAQ;AAClC,YAAM,YAAY;AAClB,UAAI,UAAU,iBAAiB;AAC7B;AAAC,QAAC,OAAuD,iBAAiB,UAAU;AAAA,MACtF;AAAA,IACF;AAAA,IACA,cAAc,OAAO,IAAI,QAAQ;AAC/B,YAAM,OAAO,IAAI;AACjB,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAI,CAAC,MAAM,SAAU,OAAM,KAAK,EAAE,OAAO,UAAU,kCAAkC,yBAAyB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAElI,YAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,YAAM,SAAS,MAAM,GAAG,QAAQ,eAAe,EAAE,IAAI,WAAW,MAAM,UAAU,KAAK,SAAS,CAAC;AAC/F,UAAI,CAAC,OAAQ,OAAM,KAAK,EAAE,OAAO,UAAU,4BAA4B,mBAAmB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAE9G,YAAM,aAAa,IAAI,mBAAmB,cAAc;AACxD,UAAI,OAAO,kBAAkB,MAAM,QAAQ,UAAU,KAAK,WAAW,SAAS,GAAG;AAC/E,YAAI,CAAC,WAAW,SAAS,OAAO,cAAc,GAAG;AAC/C,gBAAM,KAAK,EAAE,OAAO,UAAU,6BAA6B,WAAW,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC5F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,MAAM,WAAW,KAAK;AACtB,MAAM,MAAM,KAAK;AACjB,MAAM,OAAO,KAAK;AAClB,MAAM,MAAM,KAAK;AACjB,MAAM,SAAS,KAAK;AAEpB,MAAM,UAA2B;AAAA,EACtC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,OAAO;AAAA,MACP,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,sBAAsB,QAAQ,gCAAgC,CAAC;AAAA,MACvG,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,0BAA0B,QAAQ,YAAY;AAAA,QAC1E,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,YAAY;AAAA,MAClE;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,aAAa,EAAE,aAAa,oBAAoB,QAAQ,qBAAqB,aAAa,yBAAyB;AAAA,MACnH,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,4BAA4B,CAAC;AAAA,MAChG,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,YAAY;AAAA,QACnE,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,YAAY;AAAA,MAClE;AAAA,IACF;AAAA,IACA,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,aAAa,EAAE,aAAa,oBAAoB,QAAQ,qBAAqB,aAAa,oBAAoB;AAAA,MAC9G,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,4BAA4B,CAAC;AAAA,MAChG,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,YAAY;AAAA,QACnE,EAAE,QAAQ,KAAK,aAAa,aAAa,QAAQ,YAAY;AAAA,MAC/D;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,MACb,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAC;AAAA,MAC1E,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,WAAW,QAAQ,qBAAqB,CAAC;AAAA,MACjF,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,aAAa,QAAQ,YAAY;AAAA,QAC7D,EAAE,QAAQ,KAAK,aAAa,aAAa,QAAQ,YAAY;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ const metadata = {
2
+ requireAuth: true,
3
+ requireFeatures: ["webhooks.edit"],
4
+ pageTitle: "Edit Webhook",
5
+ pageTitleKey: "webhooks.form.title.edit",
6
+ pageGroup: "Integrations",
7
+ pageGroupKey: "webhooks.nav.group",
8
+ navHidden: true,
9
+ breadcrumb: [
10
+ { label: "Webhooks", labelKey: "webhooks.nav.title", href: "/backend/webhooks" },
11
+ { label: "Edit", labelKey: "common.edit" }
12
+ ]
13
+ };
14
+ export {
15
+ metadata
16
+ };
17
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/webhooks/backend/webhooks/%5Bid%5D/page.meta.ts"],
4
+ "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['webhooks.edit'],\n pageTitle: 'Edit Webhook',\n pageTitleKey: 'webhooks.form.title.edit',\n pageGroup: 'Integrations',\n pageGroupKey: 'webhooks.nav.group',\n navHidden: true,\n breadcrumb: [\n { label: 'Webhooks', labelKey: 'webhooks.nav.title', href: '/backend/webhooks' },\n { label: 'Edit', labelKey: 'common.edit' },\n ],\n}\n"],
5
+ "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,eAAe;AAAA,EACjC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,YAAY,UAAU,sBAAsB,MAAM,oBAAoB;AAAA,IAC/E,EAAE,OAAO,QAAQ,UAAU,cAAc;AAAA,EAC3C;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ const metadata = {
2
+ requireAuth: true,
3
+ requireFeatures: ["webhooks.create"],
4
+ pageTitle: "Create Webhook",
5
+ pageTitleKey: "webhooks.form.title.create",
6
+ pageGroup: "Integrations",
7
+ pageGroupKey: "webhooks.nav.group",
8
+ navHidden: true,
9
+ breadcrumb: [
10
+ { label: "Webhooks", labelKey: "webhooks.nav.title", href: "/backend/webhooks" },
11
+ { label: "Create", labelKey: "common.create" }
12
+ ]
13
+ };
14
+ export {
15
+ metadata
16
+ };
17
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/webhooks/backend/webhooks/create/page.meta.ts"],
4
+ "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['webhooks.create'],\n pageTitle: 'Create Webhook',\n pageTitleKey: 'webhooks.form.title.create',\n pageGroup: 'Integrations',\n pageGroupKey: 'webhooks.nav.group',\n navHidden: true,\n breadcrumb: [\n { label: 'Webhooks', labelKey: 'webhooks.nav.title', href: '/backend/webhooks' },\n { label: 'Create', labelKey: 'common.create' },\n ],\n}\n"],
5
+ "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,iBAAiB;AAAA,EACnC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,YAAY,UAAU,sBAAsB,MAAM,oBAAoB;AAAA,IAC/E,EAAE,OAAO,UAAU,UAAU,gBAAgB;AAAA,EAC/C;AACF;",
6
+ "names": []
7
+ }