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.
Files changed (57) hide show
  1. package/HOST.md +68 -0
  2. package/README.md +3 -0
  3. package/bridge/SandboxBridge.ts +659 -0
  4. package/bridge/context.ts +58 -0
  5. package/bridge/dataSources/dataSource.ts +63 -0
  6. package/bridge/dataSources/dataSourcePage.ts +69 -0
  7. package/bridge/dataSources/dataSourceValue.ts +19 -0
  8. package/bridge/dataSources/dateValue.ts +96 -0
  9. package/bridge/dataSources/propertySchema.ts +186 -0
  10. package/bridge/dataSources/recordPointer.ts +13 -0
  11. package/bridge/dataSources/resolve.ts +96 -0
  12. package/bridge/dataSources/resolveProperty.ts +96 -0
  13. package/bridge/hostState.ts +146 -0
  14. package/bridge/ids.ts +30 -0
  15. package/bridge/incomingType.ts +19 -0
  16. package/bridge/loadManifest.ts +54 -0
  17. package/bridge/manifest.ts +53 -0
  18. package/bridge/messages/contextChanged.ts +15 -0
  19. package/bridge/messages/createPage.ts +64 -0
  20. package/bridge/messages/createPageResult.ts +25 -0
  21. package/bridge/messages/dataSourcesChanged.ts +18 -0
  22. package/bridge/messages/getPage.ts +32 -0
  23. package/bridge/messages/getUser.ts +32 -0
  24. package/bridge/messages/hostToSandbox.ts +33 -0
  25. package/bridge/messages/init.ts +20 -0
  26. package/bridge/messages/invalidHostMessage.ts +16 -0
  27. package/bridge/messages/invalidSandboxMessage.ts +18 -0
  28. package/bridge/messages/listUsers.ts +33 -0
  29. package/bridge/messages/queryDataSource.ts +16 -0
  30. package/bridge/messages/queryDataSourceResult.ts +18 -0
  31. package/bridge/messages/ready.ts +25 -0
  32. package/bridge/messages/resize.ts +13 -0
  33. package/bridge/messages/sandboxToHost.ts +30 -0
  34. package/bridge/messages/themeChanged.ts +15 -0
  35. package/bridge/messages/updatePage.ts +21 -0
  36. package/bridge/messages/updatePageResult.ts +24 -0
  37. package/bridge/pages/page.ts +314 -0
  38. package/bridge/pendingRequests.ts +28 -0
  39. package/bridge/sandboxClient.ts +112 -0
  40. package/bridge/theme.ts +5 -0
  41. package/bridge/users/user.ts +31 -0
  42. package/docs/context.md +45 -0
  43. package/docs/data-sources.md +161 -0
  44. package/docs/lifecycle.md +92 -0
  45. package/docs/manifest.md +42 -0
  46. package/docs/pages.md +143 -0
  47. package/docs/users.md +61 -0
  48. package/host.ts +67 -0
  49. package/index.ts +86 -0
  50. package/init.ts +92 -0
  51. package/package.json +15 -5
  52. package/react.tsx +418 -0
  53. package/types.ts +157 -0
  54. package/users.ts +26 -0
  55. package/utils.ts +13 -0
  56. package/vite-plugin/index.d.ts +46 -0
  57. 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
+ }