ncblock 0.0.3 → 0.0.5
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/HOST.md +68 -0
- package/README.md +3 -0
- package/bridge/SandboxBridge.ts +659 -0
- package/bridge/context.ts +58 -0
- package/bridge/dataSources/dataSource.ts +63 -0
- package/bridge/dataSources/dataSourcePage.ts +69 -0
- package/bridge/dataSources/dataSourceValue.ts +19 -0
- package/bridge/dataSources/dateValue.ts +96 -0
- package/bridge/dataSources/propertySchema.ts +186 -0
- package/bridge/dataSources/recordPointer.ts +13 -0
- package/bridge/dataSources/resolve.ts +96 -0
- package/bridge/dataSources/resolveProperty.ts +96 -0
- package/bridge/hostState.ts +146 -0
- package/bridge/ids.ts +30 -0
- package/bridge/incomingType.ts +19 -0
- package/bridge/loadManifest.ts +54 -0
- package/bridge/manifest.ts +53 -0
- package/bridge/messages/contextChanged.ts +15 -0
- package/bridge/messages/createPage.ts +64 -0
- package/bridge/messages/createPageResult.ts +25 -0
- package/bridge/messages/dataSourcesChanged.ts +18 -0
- package/bridge/messages/getPage.ts +32 -0
- package/bridge/messages/getUser.ts +32 -0
- package/bridge/messages/hostToSandbox.ts +33 -0
- package/bridge/messages/init.ts +20 -0
- package/bridge/messages/invalidHostMessage.ts +16 -0
- package/bridge/messages/invalidSandboxMessage.ts +18 -0
- package/bridge/messages/listUsers.ts +33 -0
- package/bridge/messages/queryDataSource.ts +16 -0
- package/bridge/messages/queryDataSourceResult.ts +18 -0
- package/bridge/messages/ready.ts +25 -0
- package/bridge/messages/resize.ts +13 -0
- package/bridge/messages/sandboxToHost.ts +30 -0
- package/bridge/messages/themeChanged.ts +15 -0
- package/bridge/messages/updatePage.ts +21 -0
- package/bridge/messages/updatePageResult.ts +24 -0
- package/bridge/pages/page.ts +314 -0
- package/bridge/pendingRequests.ts +28 -0
- package/bridge/sandboxClient.ts +112 -0
- package/bridge/theme.ts +5 -0
- package/bridge/users/user.ts +31 -0
- package/docs/context.md +45 -0
- package/docs/data-sources.md +161 -0
- package/docs/lifecycle.md +92 -0
- package/docs/manifest.md +42 -0
- package/docs/pages.md +143 -0
- package/docs/users.md +61 -0
- package/host.ts +67 -0
- package/index.ts +86 -0
- package/init.ts +92 -0
- package/package.json +15 -5
- package/react.tsx +418 -0
- package/types.ts +157 -0
- package/users.ts +26 -0
- package/utils.ts +13 -0
- package/vite-plugin/index.d.ts +46 -0
- package/vite-plugin/index.js +115 -0
package/users.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getUser, listUsers } from "./bridge/sandboxClient"
|
|
2
|
+
import type {
|
|
3
|
+
GetUserResult,
|
|
4
|
+
ListUsersInput,
|
|
5
|
+
ListUsersResult,
|
|
6
|
+
NotionUserId,
|
|
7
|
+
} from "./types"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* User-related SDK APIs exposed under `sdk.users.*`.
|
|
11
|
+
*/
|
|
12
|
+
export const users = {
|
|
13
|
+
/**
|
|
14
|
+
* Lists users visible in the current custom block workspace.
|
|
15
|
+
*/
|
|
16
|
+
list(input?: ListUsersInput): Promise<ListUsersResult> {
|
|
17
|
+
return listUsers(input)
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fetches a user by id.
|
|
22
|
+
*/
|
|
23
|
+
get(userId: NotionUserId): Promise<GetUserResult> {
|
|
24
|
+
return getUser(userId)
|
|
25
|
+
},
|
|
26
|
+
}
|
package/utils.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal helpers shared across the SDK.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Throws an error when an unexpected value is encountered. This is used to ensure all code paths
|
|
7
|
+
* are covered when using discriminated unions.
|
|
8
|
+
*/
|
|
9
|
+
export function unreachable(value: never): never {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`[notion-custom-sdk] Unexpected value encountered: ${JSON.stringify(value)}`,
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for the Vite plugin. The runtime lives in `vite.js` —
|
|
3
|
+
* see that file for behavior, options, and the reasoning for splitting `.js`
|
|
4
|
+
* + `.d.ts` instead of using a single `.ts` source.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
type UserConfig = { base?: string }
|
|
8
|
+
|
|
9
|
+
type ResolvedConfig = { root: string; command: "serve" | "build" }
|
|
10
|
+
|
|
11
|
+
type ServerLike = {
|
|
12
|
+
middlewares: { use: (handler: MiddlewareHandler) => unknown }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type MiddlewareHandler = (
|
|
16
|
+
req: { url?: string },
|
|
17
|
+
res: {
|
|
18
|
+
statusCode?: number
|
|
19
|
+
setHeader: (name: string, value: string) => void
|
|
20
|
+
end: (body?: string) => void
|
|
21
|
+
},
|
|
22
|
+
next: () => void,
|
|
23
|
+
) => void
|
|
24
|
+
|
|
25
|
+
type AssetEmitterContext = {
|
|
26
|
+
emitFile: (file: {
|
|
27
|
+
type: "asset"
|
|
28
|
+
fileName: string
|
|
29
|
+
source: string
|
|
30
|
+
}) => string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type NotionCustomBlockPlugin = {
|
|
34
|
+
name: string
|
|
35
|
+
config: (userConfig: UserConfig) => { base: string }
|
|
36
|
+
configResolved: (config: ResolvedConfig) => void
|
|
37
|
+
configureServer: (server: ServerLike) => void
|
|
38
|
+
configurePreviewServer: (server: ServerLike) => void
|
|
39
|
+
buildStart: (this: AssetEmitterContext) => void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Vite plugin that serves the project's `custom_blocks.json` to the custom-block
|
|
44
|
+
* bundle in dev and emits it as a separate asset on build.
|
|
45
|
+
*/
|
|
46
|
+
export function notionCustomBlock(): NotionCustomBlockPlugin
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin half of `ncblock`. Exposes the project's
|
|
3
|
+
* `custom_blocks.json` manifest to the custom-block bundle so the SDK's runtime
|
|
4
|
+
* fetch can resolve.
|
|
5
|
+
*
|
|
6
|
+
* Authored as plain JS (with `index.d.ts` co-located for types) — the rest of
|
|
7
|
+
* the SDK is `.ts` consumed directly via the workspace symlink, but Vite's
|
|
8
|
+
* config loader resolves this subpath through Node's ESM resolver, which
|
|
9
|
+
* can't load `.ts` source files. Lives in its own `vite-plugin/` directory
|
|
10
|
+
* so it can grow its own tsconfig later.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
*
|
|
14
|
+
* import { notionCustomBlock } from "ncblock/vite"
|
|
15
|
+
*
|
|
16
|
+
* export default defineConfig({
|
|
17
|
+
* plugins: [react(), notionCustomBlock()],
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* Requires `"type": "module"` in the consuming project's `package.json` so
|
|
21
|
+
* Vite's config loader uses Node's ESM resolver (not CommonJS `require`,
|
|
22
|
+
* which fails for ESM-only deps).
|
|
23
|
+
*
|
|
24
|
+
* - **Dev (`vite`)** — middleware serves `/custom_blocks.json` from the project root.
|
|
25
|
+
* - **Build (`vite build`)** — emits `custom_blocks.json` as an asset alongside the
|
|
26
|
+
* built `index.html` so `vite preview` and any local file server can serve
|
|
27
|
+
* it. In production, the custom-block CLI handles serving.
|
|
28
|
+
*
|
|
29
|
+
* Validation is intentionally not performed here — the SDK validates on
|
|
30
|
+
* receipt, and the CLI validates separately at deploy time.
|
|
31
|
+
*/
|
|
32
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
33
|
+
import { resolve } from "node:path"
|
|
34
|
+
|
|
35
|
+
const MANIFEST_FILENAME = "custom_blocks.json"
|
|
36
|
+
const MANIFEST_URL_PATH = `/${MANIFEST_FILENAME}`
|
|
37
|
+
const REQUIRED_BASE = "./"
|
|
38
|
+
|
|
39
|
+
export function notionCustomBlock() {
|
|
40
|
+
let projectRoot = process.cwd()
|
|
41
|
+
let command = "serve"
|
|
42
|
+
|
|
43
|
+
function manifestPath() {
|
|
44
|
+
return resolve(projectRoot, MANIFEST_FILENAME)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readManifest() {
|
|
48
|
+
const file = manifestPath()
|
|
49
|
+
if (!existsSync(file)) {
|
|
50
|
+
return undefined
|
|
51
|
+
}
|
|
52
|
+
return readFileSync(file, "utf8")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function middleware(req, res, next) {
|
|
56
|
+
const path = req.url?.split("?", 1)[0]
|
|
57
|
+
if (path !== MANIFEST_URL_PATH) {
|
|
58
|
+
next()
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
const contents = readManifest()
|
|
62
|
+
if (contents === undefined) {
|
|
63
|
+
res.statusCode = 404
|
|
64
|
+
res.end()
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
res.setHeader("Content-Type", "application/json")
|
|
68
|
+
res.end(contents)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
name: "ncblock:notion-manifest",
|
|
73
|
+
config(userConfig) {
|
|
74
|
+
// Custom blocks are served from a content-addressed path that
|
|
75
|
+
// has trailing slashes, eg https://dev.notion.so/custom-block-bundle/357b35e6-e67f-81fd-b425-00e7b3e2afd1/
|
|
76
|
+
// so all asset URLs in the built bundle must be relative.
|
|
77
|
+
// Force `base: "./"` and reject any other explicit value
|
|
78
|
+
//
|
|
79
|
+
// Note: once we are set up with a wildcard subdomain host, this will no longer be necessary
|
|
80
|
+
// and should be removed, since /assets will work fine.
|
|
81
|
+
if (userConfig.base !== undefined && userConfig.base !== REQUIRED_BASE) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`ncblock/vite: \`base\` must be "${REQUIRED_BASE}" (got ${JSON.stringify(userConfig.base)}). Custom blocks need relative asset paths so the bundle works under any host-served prefix.`,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
return { base: REQUIRED_BASE }
|
|
87
|
+
},
|
|
88
|
+
configResolved(config) {
|
|
89
|
+
projectRoot = config.root
|
|
90
|
+
command = config.command
|
|
91
|
+
},
|
|
92
|
+
configureServer(server) {
|
|
93
|
+
server.middlewares.use(middleware)
|
|
94
|
+
},
|
|
95
|
+
configurePreviewServer(server) {
|
|
96
|
+
server.middlewares.use(middleware)
|
|
97
|
+
},
|
|
98
|
+
buildStart() {
|
|
99
|
+
// `emitFile` is only valid during `vite build`. In serve mode the
|
|
100
|
+
// middleware above handles `/custom_blocks.json`, so we skip emission.
|
|
101
|
+
if (command !== "build") {
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
const contents = readManifest()
|
|
105
|
+
if (contents === undefined) {
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
this.emitFile({
|
|
109
|
+
type: "asset",
|
|
110
|
+
fileName: MANIFEST_FILENAME,
|
|
111
|
+
source: contents,
|
|
112
|
+
})
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
}
|