@notionhq/workers 0.4.0 → 0.6.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/alpha/builder.d.ts +149 -0
- package/dist/alpha/builder.d.ts.map +1 -0
- package/dist/alpha/builder.js +260 -0
- package/dist/alpha/builder.test.d.ts +2 -0
- package/dist/alpha/builder.test.d.ts.map +1 -0
- package/dist/alpha/cli/build.d.ts +13 -0
- package/dist/alpha/cli/build.d.ts.map +1 -0
- package/dist/alpha/cli/build.js +36 -0
- package/dist/alpha/cli/build.test.d.ts +2 -0
- package/dist/alpha/cli/build.test.d.ts.map +1 -0
- package/dist/alpha/cli/codegen.d.ts +10 -0
- package/dist/alpha/cli/codegen.d.ts.map +1 -0
- package/dist/alpha/cli/codegen.js +41 -0
- package/dist/alpha/cli/codegen.test.d.ts +2 -0
- package/dist/alpha/cli/codegen.test.d.ts.map +1 -0
- package/dist/alpha/cli/discover.d.ts +35 -0
- package/dist/alpha/cli/discover.d.ts.map +1 -0
- package/dist/alpha/cli/discover.js +39 -0
- package/dist/alpha/cli/discover.test.d.ts +2 -0
- package/dist/alpha/cli/discover.test.d.ts.map +1 -0
- package/dist/alpha/cli/emit-manifest.d.ts +33 -0
- package/dist/alpha/cli/emit-manifest.d.ts.map +1 -0
- package/dist/alpha/cli/emit-manifest.js +266 -0
- package/dist/alpha/cli/emit-manifest.test.d.ts +2 -0
- package/dist/alpha/cli/emit-manifest.test.d.ts.map +1 -0
- package/dist/alpha/cli/index.d.ts +3 -0
- package/dist/alpha/cli/index.d.ts.map +1 -0
- package/dist/alpha/cli/index.js +36 -0
- package/dist/alpha/context.d.ts +8 -0
- package/dist/alpha/context.d.ts.map +1 -0
- package/dist/alpha/context.js +33 -0
- package/dist/alpha/database.d.ts +90 -0
- package/dist/alpha/database.d.ts.map +1 -0
- package/dist/alpha/database.js +9 -0
- package/dist/alpha/error.d.ts +41 -0
- package/dist/alpha/error.d.ts.map +1 -0
- package/dist/alpha/error.js +25 -0
- package/dist/alpha/icon-names.d.ts +6 -0
- package/dist/alpha/icon-names.d.ts.map +1 -0
- package/dist/alpha/icon-names.js +0 -0
- package/dist/alpha/json-schema.d.ts +117 -0
- package/dist/alpha/json-schema.d.ts.map +1 -0
- package/dist/alpha/json-schema.js +0 -0
- package/dist/alpha/manifest.d.ts +44 -0
- package/dist/alpha/manifest.d.ts.map +1 -0
- package/dist/alpha/manifest.js +0 -0
- package/dist/alpha/output.d.ts +7 -0
- package/dist/alpha/output.d.ts.map +1 -0
- package/dist/alpha/output.js +8 -0
- package/dist/alpha/pacer.d.ts +74 -0
- package/dist/alpha/pacer.d.ts.map +1 -0
- package/dist/alpha/pacer.js +66 -0
- package/dist/alpha/pacer.test.d.ts +2 -0
- package/dist/alpha/pacer.test.d.ts.map +1 -0
- package/dist/alpha/schedule.d.ts +6 -0
- package/dist/alpha/schedule.d.ts.map +1 -0
- package/dist/alpha/schedule.js +43 -0
- package/dist/alpha/schedule.test.d.ts +2 -0
- package/dist/alpha/schedule.test.d.ts.map +1 -0
- package/dist/alpha/schema-builder.d.ts +79 -0
- package/dist/alpha/schema-builder.d.ts.map +1 -0
- package/dist/alpha/schema-builder.js +135 -0
- package/dist/alpha/schema.d.ts +185 -0
- package/dist/alpha/schema.d.ts.map +1 -0
- package/dist/alpha/schema.js +115 -0
- package/dist/alpha/sync.d.ts +233 -0
- package/dist/alpha/sync.d.ts.map +1 -0
- package/dist/alpha/sync.js +70 -0
- package/dist/alpha/sync.test.d.ts +2 -0
- package/dist/alpha/sync.test.d.ts.map +1 -0
- package/dist/alpha/tool.d.ts +132 -0
- package/dist/alpha/tool.d.ts.map +1 -0
- package/dist/alpha/tool.js +156 -0
- package/dist/alpha/tool.test.d.ts +2 -0
- package/dist/alpha/tool.test.d.ts.map +1 -0
- package/dist/alpha/triggers.d.ts +365 -0
- package/dist/alpha/triggers.d.ts.map +1 -0
- package/dist/alpha/triggers.generated.d.ts +246 -0
- package/dist/alpha/triggers.generated.d.ts.map +1 -0
- package/dist/alpha/triggers.generated.js +239 -0
- package/dist/alpha/triggers.js +0 -0
- package/dist/alpha/types.d.ts +228 -0
- package/dist/alpha/types.d.ts.map +1 -0
- package/dist/alpha/types.js +0 -0
- package/dist/alpha/workflow.d.ts +70 -0
- package/dist/alpha/workflow.d.ts.map +1 -0
- package/dist/alpha/workflow.js +39 -0
- package/dist/alpha/workflow.test.d.ts +2 -0
- package/dist/alpha/workflow.test.d.ts.map +1 -0
- package/dist/builder.d.ts +7 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +12 -3
- package/dist/capabilities/ai_connector.d.ts.map +1 -1
- package/dist/capabilities/automation.d.ts.map +1 -1
- package/dist/capabilities/context.d.ts.map +1 -1
- package/dist/capabilities/context.js +1 -1
- package/dist/capabilities/custom-block.d.ts +124 -0
- package/dist/capabilities/custom-block.d.ts.map +1 -0
- package/dist/capabilities/custom-block.js +22 -0
- package/dist/capabilities/oauth.d.ts.map +1 -1
- package/dist/capabilities/output.d.ts.map +1 -1
- package/dist/capabilities/output.js +2 -4
- package/dist/capabilities/stateful-capability.d.ts.map +1 -1
- package/dist/capabilities/stateful-capability.js +3 -7
- package/dist/capabilities/sync.d.ts +11 -1
- package/dist/capabilities/sync.d.ts.map +1 -1
- package/dist/capabilities/sync.js +2 -8
- package/dist/capabilities/tool.d.ts.map +1 -1
- package/dist/capabilities/tool.js +6 -20
- package/dist/capabilities/webhook.d.ts.map +1 -1
- package/dist/capabilities/workflow.d.ts +50 -0
- package/dist/capabilities/workflow.d.ts.map +1 -0
- package/dist/capabilities/workflow.js +40 -0
- package/dist/capabilities/workflow.test.d.ts +2 -0
- package/dist/capabilities/workflow.test.d.ts.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/schema-builder.d.ts.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/triggers.d.ts +365 -0
- package/dist/triggers.d.ts.map +1 -0
- package/dist/triggers.generated.d.ts +246 -0
- package/dist/triggers.generated.d.ts.map +1 -0
- package/dist/triggers.generated.js +239 -0
- package/dist/triggers.js +0 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +72 -2
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +85 -4
- package/package.json +81 -14
- package/src/alpha/ajv-formats.d.ts +7 -0
- package/src/alpha/builder.test.ts +197 -0
- package/src/alpha/builder.ts +338 -0
- package/src/alpha/cli/build.test.ts +240 -0
- package/src/alpha/cli/build.ts +57 -0
- package/src/alpha/cli/codegen.test.ts +31 -0
- package/src/alpha/cli/codegen.ts +51 -0
- package/src/alpha/cli/discover.test.ts +43 -0
- package/src/alpha/cli/discover.ts +81 -0
- package/src/alpha/cli/emit-manifest.test.ts +45 -0
- package/src/alpha/cli/emit-manifest.ts +409 -0
- package/src/alpha/cli/index.ts +41 -0
- package/src/alpha/context.ts +61 -0
- package/src/alpha/database.ts +102 -0
- package/src/alpha/error.ts +49 -0
- package/src/alpha/icon-names.ts +890 -0
- package/src/alpha/json-schema.ts +180 -0
- package/src/alpha/manifest.ts +47 -0
- package/src/alpha/output.ts +8 -0
- package/src/alpha/pacer.test.ts +81 -0
- package/src/alpha/pacer.ts +181 -0
- package/src/alpha/schedule.test.ts +31 -0
- package/src/alpha/schedule.ts +53 -0
- package/src/alpha/schema-builder.ts +193 -0
- package/src/alpha/schema.ts +222 -0
- package/src/alpha/sync.test.ts +191 -0
- package/src/alpha/sync.ts +340 -0
- package/src/alpha/tool.test.ts +116 -0
- package/src/alpha/tool.ts +319 -0
- package/src/alpha/triggers.generated.ts +489 -0
- package/src/alpha/triggers.ts +500 -0
- package/src/alpha/types.ts +284 -0
- package/src/alpha/workflow.test.ts +84 -0
- package/src/alpha/workflow.ts +131 -0
- package/src/builder.test.ts +28 -60
- package/src/builder.ts +20 -7
- package/src/capabilities/ai_connector.test.ts +9 -32
- package/src/capabilities/ai_connector.ts +5 -17
- package/src/capabilities/automation.test.ts +3 -12
- package/src/capabilities/automation.ts +3 -11
- package/src/capabilities/context.ts +5 -8
- package/src/capabilities/custom-block.ts +181 -0
- package/src/capabilities/oauth.test.ts +1 -0
- package/src/capabilities/oauth.ts +1 -3
- package/src/capabilities/output.ts +1 -3
- package/src/capabilities/stateful-capability.test.ts +1 -0
- package/src/capabilities/stateful-capability.ts +3 -7
- package/src/capabilities/sync.test.ts +76 -42
- package/src/capabilities/sync.ts +16 -40
- package/src/capabilities/tool.test.ts +106 -146
- package/src/capabilities/tool.ts +17 -39
- package/src/capabilities/webhook.ts +3 -10
- package/src/capabilities/workflow.test.ts +163 -0
- package/src/capabilities/workflow.ts +112 -0
- package/src/index.ts +18 -6
- package/src/json-schema.test.ts +2 -4
- package/src/json-schema.ts +7 -6
- package/src/pacer.test.ts +1 -3
- package/src/pacer_internal.ts +1 -5
- package/src/schema-builder.test.ts +10 -35
- package/src/schema-builder.ts +6 -16
- package/src/schema.ts +2 -10
- package/src/triggers.generated.ts +489 -0
- package/src/triggers.ts +504 -0
- package/src/types.ts +21 -7
- package/src/worker.test.ts +147 -0
- package/src/worker.ts +155 -32
- package/dist/block.d.ts +0 -321
- package/dist/block.d.ts.map +0 -1
- package/src/block.ts +0 -529
- /package/dist/{block.js → alpha/ajv-formats.d.js} +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Builder } from "./builder.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Helper to extract the DateValue from a date token.
|
|
7
|
+
* Date tokens have the shape [["\u2023", [["d", dateValue]]]].
|
|
8
|
+
*/
|
|
9
|
+
function extractDateValue(token: unknown): any {
|
|
10
|
+
const arr = token as any;
|
|
11
|
+
return arr[0][1][0][1];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("Builder.date", () => {
|
|
15
|
+
it("creates a date token from YYYY-MM-DD", () => {
|
|
16
|
+
expect(extractDateValue(Builder.date("2024-01-15"))).toEqual({
|
|
17
|
+
type: "date",
|
|
18
|
+
start_date: "2024-01-15",
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("rejects non-YYYY-MM-DD strings", () => {
|
|
23
|
+
expect(() => Builder.date("01-15-2024")).toThrow("Expected YYYY-MM-DD");
|
|
24
|
+
expect(() => Builder.date("2024/01/15")).toThrow("Expected YYYY-MM-DD");
|
|
25
|
+
expect(() => Builder.date("2024-1-5")).toThrow("Expected YYYY-MM-DD");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("rejects invalid calendar dates", () => {
|
|
29
|
+
expect(() => Builder.date("2024-13-01")).toThrow();
|
|
30
|
+
// Note: "2024-02-30" is silently coerced by JS Date (rolls to March 1st),
|
|
31
|
+
// so the current validator does not catch it.
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("Builder.dateTime", () => {
|
|
36
|
+
it("parses minimal ISO 8601 (YYYY-MM-DDTHH:mm)", () => {
|
|
37
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30"))).toEqual({
|
|
38
|
+
type: "datetime",
|
|
39
|
+
start_date: "2024-01-15",
|
|
40
|
+
start_time: "10:30",
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("parses ISO 8601 with seconds", () => {
|
|
45
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30:45"))).toEqual({
|
|
46
|
+
type: "datetime",
|
|
47
|
+
start_date: "2024-01-15",
|
|
48
|
+
start_time: "10:30",
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("parses ISO 8601 with Z suffix", () => {
|
|
53
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30:00Z"))).toEqual({
|
|
54
|
+
type: "datetime",
|
|
55
|
+
start_date: "2024-01-15",
|
|
56
|
+
start_time: "10:30",
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("parses ISO 8601 with positive timezone offset", () => {
|
|
61
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30:00+05:30"))).toEqual({
|
|
62
|
+
type: "datetime",
|
|
63
|
+
start_date: "2024-01-15",
|
|
64
|
+
start_time: "10:30",
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("parses ISO 8601 with negative timezone offset", () => {
|
|
69
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30:00-08:00"))).toEqual({
|
|
70
|
+
type: "datetime",
|
|
71
|
+
start_date: "2024-01-15",
|
|
72
|
+
start_time: "10:30",
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("parses ISO 8601 with milliseconds", () => {
|
|
77
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30:00.000Z"))).toEqual({
|
|
78
|
+
type: "datetime",
|
|
79
|
+
start_date: "2024-01-15",
|
|
80
|
+
start_time: "10:30",
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("includes timeZone when provided", () => {
|
|
85
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T10:30", "America/New_York"))).toEqual({
|
|
86
|
+
type: "datetime",
|
|
87
|
+
start_date: "2024-01-15",
|
|
88
|
+
start_time: "10:30",
|
|
89
|
+
time_zone: "America/New_York",
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("handles midnight", () => {
|
|
94
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T00:00"))).toEqual({
|
|
95
|
+
type: "datetime",
|
|
96
|
+
start_date: "2024-01-15",
|
|
97
|
+
start_time: "00:00",
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("handles end of day", () => {
|
|
102
|
+
expect(extractDateValue(Builder.dateTime("2024-01-15T23:59"))).toEqual({
|
|
103
|
+
type: "datetime",
|
|
104
|
+
start_date: "2024-01-15",
|
|
105
|
+
start_time: "23:59",
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("rejects date-only strings", () => {
|
|
110
|
+
expect(() => Builder.dateTime("2024-01-15")).toThrow("Invalid ISO 8601 datetime");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("rejects plain text", () => {
|
|
114
|
+
expect(() => Builder.dateTime("not a date")).toThrow("Invalid ISO 8601 datetime");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("rejects empty string", () => {
|
|
118
|
+
expect(() => Builder.dateTime("")).toThrow("Invalid ISO 8601 datetime");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("rejects date with space instead of T", () => {
|
|
122
|
+
expect(() => Builder.dateTime("2024-01-15 10:30")).toThrow("Invalid ISO 8601 datetime");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe("Builder.dateRange", () => {
|
|
127
|
+
it("creates a date range token", () => {
|
|
128
|
+
expect(extractDateValue(Builder.dateRange("2024-01-15", "2024-01-20"))).toEqual({
|
|
129
|
+
type: "daterange",
|
|
130
|
+
start_date: "2024-01-15",
|
|
131
|
+
end_date: "2024-01-20",
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("rejects invalid start date", () => {
|
|
136
|
+
expect(() => Builder.dateRange("bad", "2024-01-20")).toThrow("Expected YYYY-MM-DD");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("rejects invalid end date", () => {
|
|
140
|
+
expect(() => Builder.dateRange("2024-01-15", "bad")).toThrow("Expected YYYY-MM-DD");
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("Builder.dateTimeRange", () => {
|
|
145
|
+
it("creates a datetime range token from ISO strings", () => {
|
|
146
|
+
expect(extractDateValue(Builder.dateTimeRange("2024-01-15T10:30", "2024-01-16T14:00"))).toEqual(
|
|
147
|
+
{
|
|
148
|
+
type: "datetimerange",
|
|
149
|
+
start_date: "2024-01-15",
|
|
150
|
+
start_time: "10:30",
|
|
151
|
+
end_date: "2024-01-16",
|
|
152
|
+
end_time: "14:00",
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("parses mixed ISO formats", () => {
|
|
158
|
+
expect(
|
|
159
|
+
extractDateValue(
|
|
160
|
+
Builder.dateTimeRange("2024-01-15T10:30:00Z", "2024-01-16T14:00:00.000+05:00"),
|
|
161
|
+
),
|
|
162
|
+
).toEqual({
|
|
163
|
+
type: "datetimerange",
|
|
164
|
+
start_date: "2024-01-15",
|
|
165
|
+
start_time: "10:30",
|
|
166
|
+
end_date: "2024-01-16",
|
|
167
|
+
end_time: "14:00",
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("includes timeZone when provided", () => {
|
|
172
|
+
expect(
|
|
173
|
+
extractDateValue(
|
|
174
|
+
Builder.dateTimeRange("2024-01-15T10:30", "2024-01-16T14:00", "Europe/London"),
|
|
175
|
+
),
|
|
176
|
+
).toEqual({
|
|
177
|
+
type: "datetimerange",
|
|
178
|
+
start_date: "2024-01-15",
|
|
179
|
+
start_time: "10:30",
|
|
180
|
+
end_date: "2024-01-16",
|
|
181
|
+
end_time: "14:00",
|
|
182
|
+
time_zone: "Europe/London",
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("rejects invalid start datetime", () => {
|
|
187
|
+
expect(() => Builder.dateTimeRange("2024-01-15", "2024-01-16T14:00")).toThrow(
|
|
188
|
+
"Invalid ISO 8601 datetime",
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("rejects invalid end datetime", () => {
|
|
193
|
+
expect(() => Builder.dateTimeRange("2024-01-15T10:30", "2024-01-16")).toThrow(
|
|
194
|
+
"Invalid ISO 8601 datetime",
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import type { NoticonName } from "./icon-names.js";
|
|
2
|
+
import type {
|
|
3
|
+
Cover,
|
|
4
|
+
DateValue,
|
|
5
|
+
Icon,
|
|
6
|
+
NoticonColor,
|
|
7
|
+
PeopleValue,
|
|
8
|
+
PlaceValue,
|
|
9
|
+
RelationReference,
|
|
10
|
+
TextValue,
|
|
11
|
+
} from "./types.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validates a date string is in YYYY-MM-DD format and represents a valid date.
|
|
15
|
+
*/
|
|
16
|
+
function validateDateString(dateString: string): void {
|
|
17
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
|
|
18
|
+
throw new Error(`Invalid date format: ${dateString}. Expected YYYY-MM-DD format.`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const date = new Date(dateString);
|
|
22
|
+
if (Number.isNaN(date.getTime())) {
|
|
23
|
+
throw new Error(`Invalid date: ${dateString}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Internal helper to create a date mention token from a DateValue object.
|
|
29
|
+
*/
|
|
30
|
+
function createDateToken(dateValue: DateValue): TextValue {
|
|
31
|
+
return [["‣", [["d", dateValue]]]];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parses an ISO 8601 datetime string into date and time components.
|
|
36
|
+
* Accepts formats like "2024-01-15T10:30", "2024-01-15T10:30:00Z",
|
|
37
|
+
* "2024-01-15T10:30:00.000+05:00", etc.
|
|
38
|
+
*/
|
|
39
|
+
function parseISODateTime(isoString: string): { date: string; time: string } {
|
|
40
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(isoString)) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Invalid ISO 8601 datetime: ${isoString}. Expected format like 2024-01-15T10:30 or 2024-01-15T10:30:00Z`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const date = isoString.slice(0, 10);
|
|
47
|
+
const time = isoString.slice(11, 16);
|
|
48
|
+
|
|
49
|
+
if (Number.isNaN(new Date(isoString).getTime())) {
|
|
50
|
+
throw new Error(`Invalid datetime: ${isoString}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { date, time };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Builders for property values in sync changes.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { Builder } from "@notionhq/workers/alpha/builder";
|
|
62
|
+
*
|
|
63
|
+
* const change = {
|
|
64
|
+
* type: "upsert",
|
|
65
|
+
* key: "task-1",
|
|
66
|
+
* properties: {
|
|
67
|
+
* "Task Name": Builder.title("Write docs"),
|
|
68
|
+
* Status: Builder.select("Open"),
|
|
69
|
+
* Due: Builder.date("2026-08-01"),
|
|
70
|
+
* Assignees: Builder.people("alice@example.com"),
|
|
71
|
+
* },
|
|
72
|
+
* };
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export const Builder = {
|
|
76
|
+
/**
|
|
77
|
+
* Creates a rich text value.
|
|
78
|
+
*/
|
|
79
|
+
richText(content: string): TextValue {
|
|
80
|
+
return [[content]];
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Creates a URL value.
|
|
85
|
+
*/
|
|
86
|
+
url(url: string): TextValue {
|
|
87
|
+
return [[url]];
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Creates a title value.
|
|
92
|
+
*/
|
|
93
|
+
title(content: string): TextValue {
|
|
94
|
+
return [[content]];
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Creates a text value.
|
|
99
|
+
*/
|
|
100
|
+
text(content: string): TextValue {
|
|
101
|
+
return [[content]];
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Creates an email value.
|
|
106
|
+
*/
|
|
107
|
+
email(email: string): TextValue {
|
|
108
|
+
return [[email]];
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Creates a phone number value.
|
|
113
|
+
*/
|
|
114
|
+
phoneNumber(phone: string): TextValue {
|
|
115
|
+
return [[phone]];
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a checkbox value.
|
|
120
|
+
*/
|
|
121
|
+
checkbox(checked: boolean): TextValue {
|
|
122
|
+
return checked ? [["Yes"]] : [["No"]];
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Creates a file URL value.
|
|
127
|
+
* @param fileUrl - The URL of the file
|
|
128
|
+
* @param fileName - Optional display name for the file (defaults to URL)
|
|
129
|
+
*/
|
|
130
|
+
file(fileUrl: string, fileName?: string): TextValue {
|
|
131
|
+
return [[fileName ?? fileUrl, [["a", fileUrl]]]];
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Creates a number value.
|
|
136
|
+
*/
|
|
137
|
+
number(value: number): TextValue {
|
|
138
|
+
if (Number.isNaN(value)) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
return [[value.toString()]];
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Creates a date value from a date string (YYYY-MM-DD).
|
|
146
|
+
*/
|
|
147
|
+
date(dateString: string): TextValue {
|
|
148
|
+
validateDateString(dateString);
|
|
149
|
+
|
|
150
|
+
return createDateToken({
|
|
151
|
+
type: "date",
|
|
152
|
+
start_date: dateString,
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Creates a datetime value from an ISO 8601 datetime string.
|
|
158
|
+
* @param isoString - An ISO 8601 datetime string (e.g., "2024-01-15T10:30", "2024-01-15T10:30:00Z")
|
|
159
|
+
* @param timeZone - Optional IANA timezone name (e.g., "America/New_York")
|
|
160
|
+
*/
|
|
161
|
+
dateTime(isoString: string, timeZone?: string): TextValue {
|
|
162
|
+
const { date, time } = parseISODateTime(isoString);
|
|
163
|
+
|
|
164
|
+
const dateValue: DateValue = {
|
|
165
|
+
type: "datetime",
|
|
166
|
+
start_date: date,
|
|
167
|
+
start_time: time,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
if (timeZone) {
|
|
171
|
+
dateValue.time_zone = timeZone;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return createDateToken(dateValue);
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Creates a date range value from date strings.
|
|
179
|
+
*/
|
|
180
|
+
dateRange(startDate: string, endDate: string): TextValue {
|
|
181
|
+
validateDateString(startDate);
|
|
182
|
+
validateDateString(endDate);
|
|
183
|
+
|
|
184
|
+
return createDateToken({
|
|
185
|
+
type: "daterange",
|
|
186
|
+
start_date: startDate,
|
|
187
|
+
end_date: endDate,
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Creates a datetime range value from ISO 8601 datetime strings.
|
|
193
|
+
* @param startDateTime - An ISO 8601 datetime string for the range start
|
|
194
|
+
* @param endDateTime - An ISO 8601 datetime string for the range end
|
|
195
|
+
* @param timeZone - Optional IANA timezone name (e.g., "America/New_York")
|
|
196
|
+
*/
|
|
197
|
+
dateTimeRange(startDateTime: string, endDateTime: string, timeZone?: string): TextValue {
|
|
198
|
+
const start = parseISODateTime(startDateTime);
|
|
199
|
+
const end = parseISODateTime(endDateTime);
|
|
200
|
+
|
|
201
|
+
const dateValue: DateValue = {
|
|
202
|
+
type: "datetimerange",
|
|
203
|
+
start_date: start.date,
|
|
204
|
+
start_time: start.time,
|
|
205
|
+
end_date: end.date,
|
|
206
|
+
end_time: end.time,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
if (timeZone) {
|
|
210
|
+
dateValue.time_zone = timeZone;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return createDateToken(dateValue);
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Creates a link with custom display text.
|
|
218
|
+
* @param displayText - The text to display
|
|
219
|
+
* @param url - The URL to link to
|
|
220
|
+
*/
|
|
221
|
+
link(displayText: string, url: string): TextValue {
|
|
222
|
+
return [[displayText, [["a", url]]]];
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Creates a select value from a single option.
|
|
227
|
+
*/
|
|
228
|
+
select(value: string): TextValue {
|
|
229
|
+
return [[value]];
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Creates a multi-select value from multiple options.
|
|
234
|
+
* @param values - Array of option names to select
|
|
235
|
+
*/
|
|
236
|
+
multiSelect(...values: string[]): TextValue {
|
|
237
|
+
if (values.length === 0) {
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
return [[values.join(",")]];
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Creates a status value from a status option name.
|
|
245
|
+
*/
|
|
246
|
+
status(value: string): TextValue {
|
|
247
|
+
return [[value]];
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Creates a people value from email addresses.
|
|
252
|
+
* @param emails - Array of email addresses for people to include
|
|
253
|
+
*/
|
|
254
|
+
people(...emails: string[]): PeopleValue {
|
|
255
|
+
return emails.map((email) => ({ email }));
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Creates a place value for a geographic location.
|
|
260
|
+
* @param value - The place value with lat/lon coordinates and optional name/address
|
|
261
|
+
*/
|
|
262
|
+
place(value: PlaceValue): PlaceValue {
|
|
263
|
+
if (typeof value.lat !== "number" || typeof value.lon !== "number") {
|
|
264
|
+
throw new Error("Place value must have numeric lat and lon coordinates");
|
|
265
|
+
}
|
|
266
|
+
return value;
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Creates a relation reference from a primary key of a related record.
|
|
271
|
+
* Use an array of relation references as the property value.
|
|
272
|
+
*
|
|
273
|
+
* @param primaryKey - The primary key of the related record
|
|
274
|
+
* @example
|
|
275
|
+
* ```typescript
|
|
276
|
+
* // Single relation
|
|
277
|
+
* { Project: [Builder.relation("project-123")] }
|
|
278
|
+
*
|
|
279
|
+
* // Multiple relations
|
|
280
|
+
* { Projects: [Builder.relation("project-123"), Builder.relation("project-456")] }
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
relation(primaryKey: string): RelationReference {
|
|
284
|
+
return { type: "primaryKey", value: primaryKey };
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Creates an emoji icon.
|
|
289
|
+
* @param emoji - An emoji string (e.g., "🎯", "✨", "🚀")
|
|
290
|
+
*/
|
|
291
|
+
emojiIcon(emoji: string): Icon {
|
|
292
|
+
return {
|
|
293
|
+
type: "emoji",
|
|
294
|
+
value: emoji,
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Creates a Notion icon with a specific color.
|
|
300
|
+
* @param icon - The name of the Notion icon (e.g., "checkmark", "pizza", "rocket")
|
|
301
|
+
* @param color - The color variant (defaults to "gray")
|
|
302
|
+
*/
|
|
303
|
+
notionIcon(icon: NoticonName, color: NoticonColor = "gray"): Icon {
|
|
304
|
+
return {
|
|
305
|
+
type: "notion",
|
|
306
|
+
icon,
|
|
307
|
+
color,
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Creates an image icon from an external URL.
|
|
313
|
+
* @param url - The URL of the image (e.g., "https://example.com/icon.png")
|
|
314
|
+
*/
|
|
315
|
+
imageIcon(url: string): Icon {
|
|
316
|
+
return {
|
|
317
|
+
type: "image",
|
|
318
|
+
url,
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Creates an image cover from an external URL.
|
|
324
|
+
* @param url - The URL of the image (e.g., "https://example.com/cover.png")
|
|
325
|
+
* @param position - Vertical image position, from 0 (top) to 1 (bottom). Defaults to 0.5.
|
|
326
|
+
*/
|
|
327
|
+
imageCover(url: string, position = 0.5): Cover {
|
|
328
|
+
if (!Number.isFinite(position) || position < 0 || position > 1) {
|
|
329
|
+
throw new Error(`Invalid cover position: ${position}. Expected a number between 0 and 1.`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
type: "image",
|
|
334
|
+
url,
|
|
335
|
+
position,
|
|
336
|
+
};
|
|
337
|
+
},
|
|
338
|
+
};
|