@dev.smartpricing/message-composer-utils 4.3.2-chat.0 → 4.3.2-fix.1
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/schemas/dynamic-values.js +1 -4
- package/dist/schemas/dynamic-values.js.map +1 -1
- package/dist/schemas/index.js +0 -1
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/message-group.js +6 -27
- package/dist/schemas/message-group.js.map +1 -1
- package/dist/schemas/onboarding.js +1 -3
- package/dist/schemas/onboarding.js.map +1 -1
- package/dist/types/app.js.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/message.js +0 -22
- package/dist/types/message.js.map +1 -1
- package/dist/utils/templates/meta.js +2 -2
- package/dist/utils/templates/meta.js.map +1 -1
- package/dist/utils/templates/meta.test.js +65 -0
- package/dist/utils/templates/meta.test.js.map +1 -0
- package/dist/utils/templates/tiptap.js +2 -5
- package/dist/utils/templates/tiptap.js.map +1 -1
- package/dist/utils/templates/whatsapp.js +26 -2
- package/dist/utils/templates/whatsapp.js.map +1 -1
- package/package.json +1 -1
- package/src/schemas/dynamic-values.ts +2 -7
- package/src/schemas/index.ts +0 -1
- package/src/schemas/message-group.ts +6 -36
- package/src/schemas/onboarding.ts +0 -3
- package/src/types/api/apiMessages.ts +0 -3
- package/src/types/app.ts +2 -7
- package/src/types/index.ts +0 -1
- package/src/types/kafka-events.ts +1 -7
- package/src/types/message.ts +0 -46
- package/src/utils/templates/meta.test.ts +86 -0
- package/src/utils/templates/meta.ts +5 -2
- package/src/utils/templates/tiptap.ts +2 -5
- package/src/utils/templates/whatsapp.ts +29 -2
- package/dist/schemas/pagination.js +0 -40
- package/dist/schemas/pagination.js.map +0 -1
- package/dist/schemas/pagination.test.js +0 -82
- package/dist/schemas/pagination.test.js.map +0 -1
- package/dist/types/api/apiTemplates.js +0 -2
- package/dist/types/api/apiTemplates.js.map +0 -1
- package/dist/types/pagination.js +0 -2
- package/dist/types/pagination.js.map +0 -1
- package/dist/types/template.js +0 -2
- package/dist/types/template.js.map +0 -1
- package/dist/utils/templates/email-maizzle.js +0 -433
- package/dist/utils/templates/email-maizzle.js.map +0 -1
- package/src/schemas/pagination.test.ts +0 -101
- package/src/schemas/pagination.ts +0 -49
- package/src/types/pagination.ts +0 -36
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
MessageFromDb,
|
|
3
3
|
MessageGroupFromDb,
|
|
4
|
-
MessageGroupProduct,
|
|
5
4
|
MessageGroupVisibility,
|
|
6
5
|
MessageStatus,
|
|
7
6
|
RenderType,
|
|
@@ -15,8 +14,6 @@ export type MessageGroupWithMessages = MessageGroupFromDb & {
|
|
|
15
14
|
export interface DuplicateMessageGroupBody {
|
|
16
15
|
name?: string;
|
|
17
16
|
visibility?: MessageGroupVisibility;
|
|
18
|
-
/** Defaults to the source group's Product. */
|
|
19
|
-
product?: MessageGroupProduct;
|
|
20
17
|
brand_id?: string | null;
|
|
21
18
|
}
|
|
22
19
|
|
package/src/types/app.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { MessageGroupProduct } from "./message.js";
|
|
2
|
-
|
|
3
1
|
export const errorCodes = {
|
|
4
2
|
INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR",
|
|
5
3
|
UNAUTHORIZED: "UNAUTHORIZED",
|
|
@@ -36,8 +34,7 @@ export interface AppError {
|
|
|
36
34
|
export interface AppContextConfig {
|
|
37
35
|
/** @deprecated No longer used — auth is cookie-based via platform layer */
|
|
38
36
|
authenticationToken?: string;
|
|
39
|
-
|
|
40
|
-
product: MessageGroupProduct;
|
|
37
|
+
product?: "connect" | "chat" | "pms" | "pricing" | "browser";
|
|
41
38
|
strategy?: "embed" | "native";
|
|
42
39
|
channels?: Array<"email" | "whatsapp">;
|
|
43
40
|
languages?: string[];
|
|
@@ -48,9 +45,7 @@ export interface AppContextConfig {
|
|
|
48
45
|
default_tags?: string[];
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
export interface AppContextState extends
|
|
52
|
-
/** Undefined when the host gave no Product; surfaced as a validation error. */
|
|
53
|
-
product?: MessageGroupProduct;
|
|
48
|
+
export interface AppContextState extends AppContextConfig {
|
|
54
49
|
initializationSource:
|
|
55
50
|
| "query"
|
|
56
51
|
| "postMessage"
|
package/src/types/index.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
MessageStatus,
|
|
3
|
-
MessageGroupCategory,
|
|
4
|
-
MessageGroupProduct,
|
|
5
|
-
} from "./message.js";
|
|
1
|
+
import type { MessageStatus, MessageGroupCategory } from "./message.js";
|
|
6
2
|
|
|
7
3
|
export interface KafkaEventBase {
|
|
8
4
|
event_id: string;
|
|
9
5
|
event_type: string;
|
|
10
6
|
timestamp: string;
|
|
11
7
|
message_group_id: string;
|
|
12
|
-
/** Product of the Message Group the event is about (ADR 0011). */
|
|
13
|
-
product: MessageGroupProduct;
|
|
14
8
|
organization_id?: string | null;
|
|
15
9
|
user_id: string;
|
|
16
10
|
}
|
package/src/types/message.ts
CHANGED
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
ButtonBlockV1,
|
|
9
9
|
} from "./whatsappblocks.v1.js";
|
|
10
10
|
import type { EmailBlock, EmailGlobalSettings } from "./emailblocks.v1.js";
|
|
11
|
-
import type { PaginationQuery, SortOrder } from "./pagination.js";
|
|
12
11
|
import {
|
|
13
12
|
brandDefaultEmailSettingsSchema,
|
|
14
13
|
brandDefaultButtonSettingsSchema,
|
|
@@ -80,55 +79,10 @@ export type MessageGroupCategory = (typeof MESSAGE_GROUP_CATEGORIES)[number];
|
|
|
80
79
|
export const MESSAGE_GROUP_VISIBILITY = ["public", "internal"] as const;
|
|
81
80
|
export type MessageGroupVisibility = (typeof MESSAGE_GROUP_VISIBILITY)[number];
|
|
82
81
|
|
|
83
|
-
/** `visibility` filter of the list route; `internal` and `all` are admin-only. */
|
|
84
|
-
export const MESSAGE_GROUP_LIST_VISIBILITY = [
|
|
85
|
-
...MESSAGE_GROUP_VISIBILITY,
|
|
86
|
-
"all",
|
|
87
|
-
] as const;
|
|
88
|
-
export type MessageGroupListVisibility =
|
|
89
|
-
(typeof MESSAGE_GROUP_LIST_VISIBILITY)[number];
|
|
90
|
-
|
|
91
|
-
/** Sortable columns of the list route (ADR 0012); aggregates are not sortable. */
|
|
92
|
-
export const MESSAGE_GROUP_LIST_SORT = [
|
|
93
|
-
"name",
|
|
94
|
-
"category",
|
|
95
|
-
"created_at",
|
|
96
|
-
"updated_at",
|
|
97
|
-
] as const;
|
|
98
|
-
export type MessageGroupListSort = (typeof MESSAGE_GROUP_LIST_SORT)[number];
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Parsed query of `GET /message-groups` (ADR 0012): what the route handler
|
|
102
|
-
* receives after defaults. The layer sends any subset of these as query params.
|
|
103
|
-
*/
|
|
104
|
-
export interface ListMessageGroupsQuery extends PaginationQuery {
|
|
105
|
-
search?: string;
|
|
106
|
-
category?: MessageGroupCategory;
|
|
107
|
-
status?: MessageStatus;
|
|
108
|
-
product?: MessageGroupProduct;
|
|
109
|
-
visibility: MessageGroupListVisibility;
|
|
110
|
-
render_type?: RenderType;
|
|
111
|
-
sort: MessageGroupListSort;
|
|
112
|
-
order: SortOrder;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* The Smartness application a Message Group is authored for (ADR 0011).
|
|
117
|
-
* Anything outside this list is not a Product and is rejected on write.
|
|
118
|
-
*/
|
|
119
|
-
export const MESSAGE_GROUP_PRODUCTS = [
|
|
120
|
-
"connect",
|
|
121
|
-
"chat",
|
|
122
|
-
"pms",
|
|
123
|
-
"pricing",
|
|
124
|
-
] as const;
|
|
125
|
-
export type MessageGroupProduct = (typeof MESSAGE_GROUP_PRODUCTS)[number];
|
|
126
|
-
|
|
127
82
|
export interface MessageGroup extends DbEntity {
|
|
128
83
|
id: string;
|
|
129
84
|
name: string;
|
|
130
85
|
category: MessageGroupCategory;
|
|
131
|
-
product: MessageGroupProduct;
|
|
132
86
|
visibility?: MessageGroupVisibility | null;
|
|
133
87
|
brand_id?: string | null;
|
|
134
88
|
organization_id?: string | null;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import type { JSONContent } from "@tiptap/core";
|
|
3
|
+
import type {
|
|
4
|
+
MetaHeaderComponent,
|
|
5
|
+
WhatsappMessage,
|
|
6
|
+
WithDbTimestamps,
|
|
7
|
+
} from "../../types/index.js";
|
|
8
|
+
import { translateWhatsappToMeta } from "./meta.js";
|
|
9
|
+
import { getWhatsappEmpty } from "./whatsapp.js";
|
|
10
|
+
|
|
11
|
+
function messageWithHeader(
|
|
12
|
+
content: JSONContent,
|
|
13
|
+
): WithDbTimestamps<WhatsappMessage> {
|
|
14
|
+
const base = getWhatsappEmpty("en");
|
|
15
|
+
return {
|
|
16
|
+
...base,
|
|
17
|
+
id: "msg-1",
|
|
18
|
+
body: {
|
|
19
|
+
...base.body,
|
|
20
|
+
header: { type: "text", content },
|
|
21
|
+
body: {
|
|
22
|
+
enabled: true,
|
|
23
|
+
content: {
|
|
24
|
+
type: "doc",
|
|
25
|
+
content: [
|
|
26
|
+
{ type: "paragraph", content: [{ type: "text", text: "Body" }] },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
created_at: "2026-01-01T00:00:00.000Z",
|
|
32
|
+
updated_at: "2026-01-01T00:00:00.000Z",
|
|
33
|
+
} as WithDbTimestamps<WhatsappMessage>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function headerText(content: JSONContent): string | undefined {
|
|
37
|
+
const template = translateWhatsappToMeta(
|
|
38
|
+
messageWithHeader(content),
|
|
39
|
+
"group",
|
|
40
|
+
"utility",
|
|
41
|
+
"pfx",
|
|
42
|
+
"en",
|
|
43
|
+
);
|
|
44
|
+
const header = template.components.find(
|
|
45
|
+
(c): c is MetaHeaderComponent => c.type === "HEADER",
|
|
46
|
+
);
|
|
47
|
+
return header && "text" in header ? header.text : undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("translateWhatsappToMeta header", () => {
|
|
51
|
+
it("sends header text to Meta without WhatsApp formatting markers", () => {
|
|
52
|
+
const content: JSONContent = {
|
|
53
|
+
type: "doc",
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "paragraph",
|
|
57
|
+
content: [
|
|
58
|
+
{ type: "text", text: "Your ", marks: [{ type: "bold" }] },
|
|
59
|
+
{ type: "text", text: "stay", marks: [{ type: "italic" }] },
|
|
60
|
+
{ type: "text", text: " is confirmed" },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
expect(headerText(content)).toBe("Your stay is confirmed");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("sends header text to Meta without emojis", () => {
|
|
70
|
+
const content: JSONContent = {
|
|
71
|
+
type: "doc",
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: "paragraph",
|
|
75
|
+
content: [
|
|
76
|
+
{ type: "text", text: "Welcome " },
|
|
77
|
+
{ type: "emoji", attrs: { name: "wave" } },
|
|
78
|
+
{ type: "text", text: " {{guest_name}}" },
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
expect(headerText(content)).toBe("Welcome {{guest_name}}");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -16,7 +16,10 @@ import {
|
|
|
16
16
|
WA_HEADER_TEXT_MAX_LENGTH,
|
|
17
17
|
WA_FOOTER_MAX_LENGTH,
|
|
18
18
|
} from "../../types/index.js";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
convertToWhatsappHeaderText,
|
|
21
|
+
convertToWhatsappMarkdown,
|
|
22
|
+
} from "./whatsapp.js";
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Generates a unique template name for Meta
|
|
@@ -135,7 +138,7 @@ function translateHeaderToMeta(
|
|
|
135
138
|
}
|
|
136
139
|
case "text": {
|
|
137
140
|
if (!header.content) return null;
|
|
138
|
-
const text =
|
|
141
|
+
const text = convertToWhatsappHeaderText(header.content);
|
|
139
142
|
const exampleContent = generateExampleContent(text, "header");
|
|
140
143
|
|
|
141
144
|
const result: MetaHeaderComponent = {
|
|
@@ -67,11 +67,8 @@ const PRESETS: Record<
|
|
|
67
67
|
italic: true,
|
|
68
68
|
emoji: true,
|
|
69
69
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
italic: true,
|
|
73
|
-
emoji: true,
|
|
74
|
-
},
|
|
70
|
+
// Meta rejects formatting and emojis in header text
|
|
71
|
+
"whatsapp-header": {},
|
|
75
72
|
email: {
|
|
76
73
|
bold: true,
|
|
77
74
|
italic: true,
|
|
@@ -78,13 +78,13 @@ export function isWhatsappValid(
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
// Validate header text length (use
|
|
81
|
+
// Validate header text length (use the text Meta receives)
|
|
82
82
|
if (
|
|
83
83
|
message.body.header.type === "text" &&
|
|
84
84
|
message.body.header.content &&
|
|
85
85
|
!isContentEmpty(message.body.header.content)
|
|
86
86
|
) {
|
|
87
|
-
const headerText =
|
|
87
|
+
const headerText = convertToWhatsappHeaderText(message.body.header.content);
|
|
88
88
|
if (headerText.length > WA_HEADER_TEXT_MAX_LENGTH) {
|
|
89
89
|
errors.push("editor.validation.error.headerTooLong");
|
|
90
90
|
}
|
|
@@ -305,6 +305,33 @@ export function convertToWhatsappMarkdown(
|
|
|
305
305
|
return processNode(content);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Converts a WhatsApp header to the text Meta receives.
|
|
310
|
+
* Meta rejects formatting in header text ("Header Format is Incorrect",
|
|
311
|
+
* subcode 2388072), so marks and emoji nodes are dropped — including on
|
|
312
|
+
* legacy content saved before the header editor stopped offering them.
|
|
313
|
+
*/
|
|
314
|
+
export function convertToWhatsappHeaderText(
|
|
315
|
+
content: Content | undefined,
|
|
316
|
+
): string {
|
|
317
|
+
return convertToWhatsappMarkdown(toPlainHeader(content));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function toPlainHeader(content: Content | undefined): Content | undefined {
|
|
321
|
+
if (Array.isArray(content))
|
|
322
|
+
return content.map((n) => toPlainHeader(n) as JSONContent);
|
|
323
|
+
if (!content || typeof content !== "object") return content;
|
|
324
|
+
const { marks: _marks, ...node } = content;
|
|
325
|
+
return node.content
|
|
326
|
+
? {
|
|
327
|
+
...node,
|
|
328
|
+
content: node.content
|
|
329
|
+
.filter((n) => n.type !== "emoji")
|
|
330
|
+
.map((n) => toPlainHeader(n) as JSONContent),
|
|
331
|
+
}
|
|
332
|
+
: node;
|
|
333
|
+
}
|
|
334
|
+
|
|
308
335
|
/**
|
|
309
336
|
* Calculates the translation completion percentage for a WhatsApp message
|
|
310
337
|
* Compares against a base message to determine which fields need translation
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export const PAGINATION_DEFAULT_PER_PAGE = 25;
|
|
3
|
-
export const PAGINATION_MAX_PER_PAGE = 100;
|
|
4
|
-
/** Laravel-style offset pagination query params (ADR 0012). */
|
|
5
|
-
export const paginationQuerySchema = z.object({
|
|
6
|
-
page: z.coerce.number().int().min(1).default(1),
|
|
7
|
-
per_page: z.coerce
|
|
8
|
-
.number()
|
|
9
|
-
.int()
|
|
10
|
-
.min(1)
|
|
11
|
-
.max(PAGINATION_MAX_PER_PAGE)
|
|
12
|
-
.default(PAGINATION_DEFAULT_PER_PAGE),
|
|
13
|
-
});
|
|
14
|
-
export const paginationLinksSchema = z.object({
|
|
15
|
-
first: z.string(),
|
|
16
|
-
last: z.string(),
|
|
17
|
-
prev: z.string().nullable(),
|
|
18
|
-
next: z.string().nullable(),
|
|
19
|
-
});
|
|
20
|
-
export const paginationMetaSchema = z.object({
|
|
21
|
-
current_page: z.number().int(),
|
|
22
|
-
from: z.number().int().nullable(),
|
|
23
|
-
last_page: z.number().int(),
|
|
24
|
-
path: z.string(),
|
|
25
|
-
per_page: z.number().int(),
|
|
26
|
-
to: z.number().int().nullable(),
|
|
27
|
-
total: z.number().int(),
|
|
28
|
-
});
|
|
29
|
-
/**
|
|
30
|
-
* Laravel API resource-collection envelope around `item`:
|
|
31
|
-
* `{ data, links: { first, last, prev, next }, meta: { … } }`, no `meta.links`.
|
|
32
|
-
*/
|
|
33
|
-
export function paginatedResponseSchema(item) {
|
|
34
|
-
return z.object({
|
|
35
|
-
data: z.array(item),
|
|
36
|
-
links: paginationLinksSchema,
|
|
37
|
-
meta: paginationMetaSchema,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=pagination.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/schemas/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM;SACf,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,uBAAuB,CAAC;SAC5B,OAAO,CAAC,2BAA2B,CAAC;CACxC,CAA+C,CAAC;AAEjD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAA+C,CAAC;AAEjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC1B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;CACxB,CAA8C,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAsB,IAAO;IAClE,OAAO,CAAC,CAAC,MAAM,CAAC;QACd,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QACnB,KAAK,EAAE,qBAAqB;QAC5B,IAAI,EAAE,oBAAoB;KAC3B,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { paginationQuerySchema, paginatedResponseSchema, } from "./pagination.js";
|
|
4
|
-
describe("paginationQuerySchema", () => {
|
|
5
|
-
it("defaults to page 1 and 25 per page", () => {
|
|
6
|
-
expect(paginationQuerySchema.parse({})).toEqual({ page: 1, per_page: 25 });
|
|
7
|
-
});
|
|
8
|
-
it("coerces query-string numbers", () => {
|
|
9
|
-
expect(paginationQuerySchema.parse({ page: "3", per_page: "50" })).toEqual({
|
|
10
|
-
page: 3,
|
|
11
|
-
per_page: 50,
|
|
12
|
-
});
|
|
13
|
-
});
|
|
14
|
-
it("accepts the bounds 1 and 100 for per_page", () => {
|
|
15
|
-
expect(paginationQuerySchema.parse({ per_page: "1" }).per_page).toBe(1);
|
|
16
|
-
expect(paginationQuerySchema.parse({ per_page: "100" }).per_page).toBe(100);
|
|
17
|
-
});
|
|
18
|
-
it("rejects page 0, per_page 0 and per_page 101", () => {
|
|
19
|
-
expect(paginationQuerySchema.safeParse({ page: "0" }).success).toBe(false);
|
|
20
|
-
expect(paginationQuerySchema.safeParse({ per_page: "0" }).success).toBe(false);
|
|
21
|
-
expect(paginationQuerySchema.safeParse({ per_page: "101" }).success).toBe(false);
|
|
22
|
-
});
|
|
23
|
-
it("rejects non-integer values", () => {
|
|
24
|
-
expect(paginationQuerySchema.safeParse({ page: "1.5" }).success).toBe(false);
|
|
25
|
-
expect(paginationQuerySchema.safeParse({ page: "abc" }).success).toBe(false);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
describe("paginatedResponseSchema", () => {
|
|
29
|
-
const schema = paginatedResponseSchema(z.object({ id: z.string() }));
|
|
30
|
-
it("accepts the Laravel resource-collection envelope", () => {
|
|
31
|
-
const envelope = {
|
|
32
|
-
data: [{ id: "a" }],
|
|
33
|
-
links: { first: "/x?page=1", last: "/x?page=1", prev: null, next: null },
|
|
34
|
-
meta: {
|
|
35
|
-
current_page: 1,
|
|
36
|
-
from: 1,
|
|
37
|
-
last_page: 1,
|
|
38
|
-
path: "/x",
|
|
39
|
-
per_page: 25,
|
|
40
|
-
to: 1,
|
|
41
|
-
total: 1,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
expect(schema.parse(envelope)).toEqual(envelope);
|
|
45
|
-
});
|
|
46
|
-
it("allows null from/to on an empty page and has no meta.links", () => {
|
|
47
|
-
const parsed = schema.parse({
|
|
48
|
-
data: [],
|
|
49
|
-
links: { first: "/x?page=1", last: "/x?page=1", prev: null, next: null },
|
|
50
|
-
meta: {
|
|
51
|
-
current_page: 1,
|
|
52
|
-
from: null,
|
|
53
|
-
last_page: 1,
|
|
54
|
-
path: "/x",
|
|
55
|
-
per_page: 25,
|
|
56
|
-
to: null,
|
|
57
|
-
total: 0,
|
|
58
|
-
links: [{ url: null, label: "x", active: false }],
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
expect(parsed.meta.from).toBeNull();
|
|
62
|
-
expect(parsed.meta.to).toBeNull();
|
|
63
|
-
expect("links" in parsed.meta).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
it("validates items with the given schema", () => {
|
|
66
|
-
const result = schema.safeParse({
|
|
67
|
-
data: [{ id: 1 }],
|
|
68
|
-
links: { first: "/x?page=1", last: "/x?page=1", prev: null, next: null },
|
|
69
|
-
meta: {
|
|
70
|
-
current_page: 1,
|
|
71
|
-
from: 1,
|
|
72
|
-
last_page: 1,
|
|
73
|
-
path: "/x",
|
|
74
|
-
per_page: 25,
|
|
75
|
-
to: 1,
|
|
76
|
-
total: 1,
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
expect(result.success).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
//# sourceMappingURL=pagination.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.test.js","sourceRoot":"","sources":["../../src/schemas/pagination.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"apiTemplates.js","sourceRoot":"","sources":["../../../src/types/api/apiTemplates.ts"],"names":[],"mappings":""}
|
package/dist/types/pagination.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/types/pagination.ts"],"names":[],"mappings":"AAkCA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,CAAU,CAAC"}
|
package/dist/types/template.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/types/template.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,cAAc,GAAG,QAAiB,CAAC"}
|