@notionhq/custom-blocks-host 0.3.6 → 0.3.8
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/README.md +5 -0
- package/dist/browser.js +1 -1
- package/dist/dateValue.d.ts +11 -0
- package/dist/dateValue.d.ts.map +1 -0
- package/dist/dateValue.js +96 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lifecycle/legacyPage.d.ts.map +1 -1
- package/dist/lifecycle/legacyPage.js +14 -62
- package/dist/protocol/dataSources/dateValue.d.ts +2 -2
- package/dist/protocol/dataSources/dateValue.js +9 -7
- package/dist/protocol/messages/createPage.d.ts +64 -2
- package/dist/protocol/messages/createPageResult.d.ts +192 -6
- package/dist/protocol/messages/getPage.d.ts +192 -6
- package/dist/protocol/messages/hostToSandbox.d.ts +704 -22
- package/dist/protocol/messages/queryDataSourceResult.d.ts +128 -4
- package/dist/protocol/messages/sandboxToHost.d.ts +128 -4
- package/dist/protocol/messages/updatePage.d.ts +64 -2
- package/dist/protocol/messages/updatePageResult.d.ts +192 -6
- package/dist/protocol/pages/page.d.ts +360 -12
- package/dist/protocol/pages/page.js +48 -2
- package/package.json +1 -1
- package/src/dateValue.ts +120 -0
- package/src/index.ts +5 -0
- package/src/lifecycle/legacyPage.ts +14 -73
package/src/dateValue.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NotionDate,
|
|
3
|
+
NotionDateRange,
|
|
4
|
+
NotionDateTime,
|
|
5
|
+
NotionDateTimeRange,
|
|
6
|
+
} from "@notionhq/custom-blocks-protocol/dataSources/dateValue.js"
|
|
7
|
+
import type { NotionDateInput } from "@notionhq/custom-blocks-protocol/pages/page.js"
|
|
8
|
+
|
|
9
|
+
export type CustomBlockDateValue =
|
|
10
|
+
| NotionDate
|
|
11
|
+
| NotionDateRange
|
|
12
|
+
| (NotionDateTime & { time_zone: string })
|
|
13
|
+
| (NotionDateTimeRange & { time_zone: string })
|
|
14
|
+
|
|
15
|
+
export class InvalidNotionDateError extends Error {}
|
|
16
|
+
|
|
17
|
+
export function toNotionDateValue(
|
|
18
|
+
value: NotionDateInput,
|
|
19
|
+
): CustomBlockDateValue {
|
|
20
|
+
try {
|
|
21
|
+
return convertDateValue(value)
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error instanceof RangeError) {
|
|
24
|
+
throw new InvalidNotionDateError(error.message)
|
|
25
|
+
}
|
|
26
|
+
throw error
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function convertDateValue(value: NotionDateInput): CustomBlockDateValue {
|
|
31
|
+
const { start, end, time_zone, reminder } = value
|
|
32
|
+
if (!start.split("T")[0]) {
|
|
33
|
+
throw new InvalidNotionDateError("Date values must include a date.")
|
|
34
|
+
}
|
|
35
|
+
const timed = start.includes("T") || time_zone != null
|
|
36
|
+
const offset = start.match(/([+-])(\d{2}):(\d{2})$/)
|
|
37
|
+
const offsetMinutes = offset
|
|
38
|
+
? (Number(offset[2]) * 60 + Number(offset[3])) *
|
|
39
|
+
(offset[1] === "-" ? -1 : 1)
|
|
40
|
+
: 0
|
|
41
|
+
const fixedZone = time_zone?.match(/^UTC(?:([+-])(\d{1,2})(?::(\d{2}))?)?$/)
|
|
42
|
+
const targetOffsetMinutes = fixedZone
|
|
43
|
+
? (Number(fixedZone[2] ?? 0) * 60 + Number(fixedZone[3] ?? 0)) *
|
|
44
|
+
(fixedZone[1] === "-" ? -1 : 1)
|
|
45
|
+
: offsetMinutes
|
|
46
|
+
const parts = (input: string) => {
|
|
47
|
+
if (!input.split("T")[0]) {
|
|
48
|
+
throw new InvalidNotionDateError("Date values must include a date.")
|
|
49
|
+
}
|
|
50
|
+
if (!input.includes("T")) {
|
|
51
|
+
return { date: input, time: "00:00" }
|
|
52
|
+
}
|
|
53
|
+
const wallClock = input.match(
|
|
54
|
+
/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})(?::\d{2}(?:\.\d+)?)?$/,
|
|
55
|
+
)
|
|
56
|
+
if (wallClock) {
|
|
57
|
+
return { date: wallClock[1], time: wallClock[2] }
|
|
58
|
+
}
|
|
59
|
+
if (!time_zone || fixedZone) {
|
|
60
|
+
const local = new Date(
|
|
61
|
+
new Date(input).getTime() + targetOffsetMinutes * 60_000,
|
|
62
|
+
).toISOString()
|
|
63
|
+
return { date: local.slice(0, 10), time: local.slice(11, 16) }
|
|
64
|
+
}
|
|
65
|
+
const entries = new Intl.DateTimeFormat("en-CA", {
|
|
66
|
+
timeZone: time_zone,
|
|
67
|
+
year: "numeric",
|
|
68
|
+
month: "2-digit",
|
|
69
|
+
day: "2-digit",
|
|
70
|
+
hour: "2-digit",
|
|
71
|
+
minute: "2-digit",
|
|
72
|
+
hourCycle: "h23",
|
|
73
|
+
}).formatToParts(new Date(input))
|
|
74
|
+
const get = (type: string) =>
|
|
75
|
+
entries.find(part => part.type === type)?.value
|
|
76
|
+
return {
|
|
77
|
+
date: `${get("year")}-${get("month")}-${get("day")}`,
|
|
78
|
+
time: `${get("hour")}:${get("minute")}`,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const startParts = parts(start)
|
|
82
|
+
const endParts = end ? parts(end) : undefined
|
|
83
|
+
if (!timed) {
|
|
84
|
+
if (reminder && !("time" in reminder) && reminder.unit !== "none") {
|
|
85
|
+
throw new InvalidNotionDateError(
|
|
86
|
+
"Hour and minute reminders require a date with a time.",
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
return endParts
|
|
90
|
+
? {
|
|
91
|
+
type: "daterange",
|
|
92
|
+
start_date: startParts.date,
|
|
93
|
+
end_date: endParts.date,
|
|
94
|
+
reminder,
|
|
95
|
+
}
|
|
96
|
+
: { type: "date", start_date: startParts.date, reminder }
|
|
97
|
+
}
|
|
98
|
+
const zone =
|
|
99
|
+
time_zone ??
|
|
100
|
+
(offsetMinutes === 0
|
|
101
|
+
? "UTC"
|
|
102
|
+
: `UTC${offsetMinutes < 0 ? "-" : "+"}${Math.floor(Math.abs(offsetMinutes) / 60)}${Math.abs(offsetMinutes) % 60 === 0 ? "" : `:${String(Math.abs(offsetMinutes) % 60).padStart(2, "0")}`}`)
|
|
103
|
+
return endParts
|
|
104
|
+
? {
|
|
105
|
+
type: "datetimerange",
|
|
106
|
+
start_date: startParts.date,
|
|
107
|
+
start_time: startParts.time,
|
|
108
|
+
end_date: endParts.date,
|
|
109
|
+
end_time: endParts.time,
|
|
110
|
+
time_zone: zone,
|
|
111
|
+
reminder,
|
|
112
|
+
}
|
|
113
|
+
: {
|
|
114
|
+
type: "datetime",
|
|
115
|
+
start_date: startParts.date,
|
|
116
|
+
start_time: startParts.time,
|
|
117
|
+
time_zone: zone,
|
|
118
|
+
reminder,
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -55,6 +55,11 @@ export {
|
|
|
55
55
|
type CustomBlockHostOptions,
|
|
56
56
|
createCustomBlockHost,
|
|
57
57
|
} from "./createCustomBlockHost.js"
|
|
58
|
+
export {
|
|
59
|
+
type CustomBlockDateValue,
|
|
60
|
+
InvalidNotionDateError,
|
|
61
|
+
toNotionDateValue,
|
|
62
|
+
} from "./dateValue.js"
|
|
58
63
|
export { toNotionPageId } from "./ids.js"
|
|
59
64
|
export type { CustomBlockHostManifestOptions } from "./lifecycle/manifestOptions.js"
|
|
60
65
|
export type {
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
notionPageDataSchema,
|
|
6
6
|
} from "@notionhq/custom-blocks-protocol/pages/page.js"
|
|
7
7
|
import type { InferOutput } from "valibot"
|
|
8
|
+
import { toNotionDateValue } from "../dateValue.js"
|
|
8
9
|
import { unreachable } from "../utils.js"
|
|
9
10
|
|
|
10
11
|
export function toLegacyPage(
|
|
@@ -78,78 +79,6 @@ function timestamp(
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
function legacyDate(value: {
|
|
82
|
-
start: string
|
|
83
|
-
end?: string | null
|
|
84
|
-
time_zone?: string | null
|
|
85
|
-
}): NotionDataSourceValue {
|
|
86
|
-
const timed = value.start.includes("T") || value.time_zone != null
|
|
87
|
-
const offset = value.start.match(/([+-])(\d{2}):(\d{2})$/)
|
|
88
|
-
const offsetMinutes = offset
|
|
89
|
-
? (Number(offset[2]) * 60 + Number(offset[3])) *
|
|
90
|
-
(offset[1] === "-" ? -1 : 1)
|
|
91
|
-
: 0
|
|
92
|
-
const parts = (input: string) => {
|
|
93
|
-
if (!input.includes("T")) {
|
|
94
|
-
return { date: input, time: "00:00" }
|
|
95
|
-
}
|
|
96
|
-
const wallClock = input.match(
|
|
97
|
-
/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})(?::\d{2}(?:\.\d+)?)?$/,
|
|
98
|
-
)
|
|
99
|
-
if (wallClock) {
|
|
100
|
-
return { date: wallClock[1], time: wallClock[2] }
|
|
101
|
-
}
|
|
102
|
-
if (!value.time_zone) {
|
|
103
|
-
const local = new Date(
|
|
104
|
-
new Date(input).getTime() + offsetMinutes * 60_000,
|
|
105
|
-
).toISOString()
|
|
106
|
-
return { date: local.slice(0, 10), time: local.slice(11, 16) }
|
|
107
|
-
}
|
|
108
|
-
const entries = new Intl.DateTimeFormat("en-CA", {
|
|
109
|
-
timeZone: value.time_zone,
|
|
110
|
-
year: "numeric",
|
|
111
|
-
month: "2-digit",
|
|
112
|
-
day: "2-digit",
|
|
113
|
-
hour: "2-digit",
|
|
114
|
-
minute: "2-digit",
|
|
115
|
-
hourCycle: "h23",
|
|
116
|
-
}).formatToParts(new Date(input))
|
|
117
|
-
const get = (type: string) =>
|
|
118
|
-
entries.find(part => part.type === type)?.value
|
|
119
|
-
return {
|
|
120
|
-
date: `${get("year")}-${get("month")}-${get("day")}`,
|
|
121
|
-
time: `${get("hour")}:${get("minute")}`,
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const start = parts(value.start)
|
|
125
|
-
const end = value.end ? parts(value.end) : undefined
|
|
126
|
-
if (!timed) {
|
|
127
|
-
return end
|
|
128
|
-
? { type: "daterange", start_date: start.date, end_date: end.date }
|
|
129
|
-
: { type: "date", start_date: start.date }
|
|
130
|
-
}
|
|
131
|
-
const zone =
|
|
132
|
-
value.time_zone ??
|
|
133
|
-
(offsetMinutes === 0
|
|
134
|
-
? "UTC"
|
|
135
|
-
: `UTC${offsetMinutes < 0 ? "-" : "+"}${Math.floor(Math.abs(offsetMinutes) / 60)}${Math.abs(offsetMinutes) % 60 === 0 ? "" : `:${String(Math.abs(offsetMinutes) % 60).padStart(2, "0")}`}`)
|
|
136
|
-
return end
|
|
137
|
-
? {
|
|
138
|
-
type: "datetimerange",
|
|
139
|
-
start_date: start.date,
|
|
140
|
-
start_time: start.time,
|
|
141
|
-
end_date: end.date,
|
|
142
|
-
end_time: end.time,
|
|
143
|
-
time_zone: zone,
|
|
144
|
-
}
|
|
145
|
-
: {
|
|
146
|
-
type: "datetime",
|
|
147
|
-
start_date: start.date,
|
|
148
|
-
start_time: start.time,
|
|
149
|
-
time_zone: zone,
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
82
|
function toLegacyProperty(
|
|
154
83
|
property: NotionPagePropertyValue,
|
|
155
84
|
): NotionDataSourceValue | undefined {
|
|
@@ -175,7 +104,7 @@ function toLegacyProperty(
|
|
|
175
104
|
case "multi_select":
|
|
176
105
|
return property.multi_select.flatMap(option => option.name ?? [])
|
|
177
106
|
case "date":
|
|
178
|
-
return property.date ?
|
|
107
|
+
return property.date ? toNotionDateValue(property.date) : undefined
|
|
179
108
|
case "people":
|
|
180
109
|
return property.people.map(person =>
|
|
181
110
|
person.object === "group"
|
|
@@ -190,6 +119,18 @@ function toLegacyProperty(
|
|
|
190
119
|
return property.relation.map(page => ({ id: page.id, table: "block" }))
|
|
191
120
|
case "files":
|
|
192
121
|
return property.files.map(file => file.name).join(",")
|
|
122
|
+
case "unique_id":
|
|
123
|
+
return property.unique_id
|
|
124
|
+
case "button":
|
|
125
|
+
return property.button
|
|
126
|
+
case "formula":
|
|
127
|
+
return property.formula
|
|
128
|
+
case "location":
|
|
129
|
+
return property.location
|
|
130
|
+
case "rollup":
|
|
131
|
+
return property.rollup
|
|
132
|
+
case "verification":
|
|
133
|
+
return property.verification
|
|
193
134
|
case "place":
|
|
194
135
|
return ""
|
|
195
136
|
case "created_time":
|