@notis_ai/cli 0.2.0-beta.16.1 → 0.2.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.
Files changed (39) hide show
  1. package/README.md +4 -6
  2. package/package.json +1 -6
  3. package/src/command-specs/apps.js +10 -77
  4. package/src/runtime/app-platform.js +69 -309
  5. package/src/runtime/app-preview-server.js +96 -136
  6. package/template/app/globals.css +0 -3
  7. package/template/app/layout.tsx +0 -7
  8. package/template/app/page.tsx +0 -55
  9. package/template/components/ui/badge.tsx +0 -28
  10. package/template/components/ui/button.tsx +0 -53
  11. package/template/components/ui/card.tsx +0 -56
  12. package/template/components.json +0 -20
  13. package/template/lib/utils.ts +0 -6
  14. package/template/notis.config.ts +0 -18
  15. package/template/package.json +0 -32
  16. package/template/packages/notis-sdk/package.json +0 -26
  17. package/template/packages/notis-sdk/src/config.ts +0 -48
  18. package/template/packages/notis-sdk/src/helpers.ts +0 -131
  19. package/template/packages/notis-sdk/src/hooks/useAppState.ts +0 -50
  20. package/template/packages/notis-sdk/src/hooks/useBackend.ts +0 -41
  21. package/template/packages/notis-sdk/src/hooks/useCollectionItem.ts +0 -58
  22. package/template/packages/notis-sdk/src/hooks/useDatabase.ts +0 -87
  23. package/template/packages/notis-sdk/src/hooks/useDocument.ts +0 -61
  24. package/template/packages/notis-sdk/src/hooks/useNotis.ts +0 -31
  25. package/template/packages/notis-sdk/src/hooks/useNotisNavigation.ts +0 -49
  26. package/template/packages/notis-sdk/src/hooks/useTool.ts +0 -49
  27. package/template/packages/notis-sdk/src/hooks/useTools.ts +0 -56
  28. package/template/packages/notis-sdk/src/hooks/useUpsertDocument.ts +0 -57
  29. package/template/packages/notis-sdk/src/index.ts +0 -47
  30. package/template/packages/notis-sdk/src/provider.tsx +0 -44
  31. package/template/packages/notis-sdk/src/runtime.ts +0 -159
  32. package/template/packages/notis-sdk/src/styles.css +0 -123
  33. package/template/packages/notis-sdk/src/ui.ts +0 -15
  34. package/template/packages/notis-sdk/src/vite.ts +0 -54
  35. package/template/packages/notis-sdk/tsconfig.json +0 -15
  36. package/template/postcss.config.mjs +0 -8
  37. package/template/tailwind.config.ts +0 -58
  38. package/template/tsconfig.json +0 -22
  39. package/template/vite.config.ts +0 -10
@@ -1,57 +0,0 @@
1
- 'use client';
2
-
3
- import { useCallback, useState } from 'react';
4
- import { useNotisRuntime } from '../provider';
5
- import type { DocumentRecord } from '../runtime';
6
-
7
- interface UpsertArgs {
8
- databaseSlug: string;
9
- documentId?: string;
10
- title?: string;
11
- properties?: Record<string, unknown>;
12
- }
13
-
14
- interface UseUpsertDocumentResult {
15
- upsert: (args: UpsertArgs) => Promise<DocumentRecord>;
16
- loading: boolean;
17
- error: Error | null;
18
- }
19
-
20
- /**
21
- * Create or update a document in a Notis database.
22
- *
23
- * ```tsx
24
- * const { upsert, loading } = useUpsertDocument();
25
- * await upsert({ databaseSlug: 'tasks', title: 'New task', properties: { status: 'Open' } });
26
- * ```
27
- */
28
- export function useUpsertDocument(): UseUpsertDocumentResult {
29
- const runtime = useNotisRuntime();
30
- const [loading, setLoading] = useState(false);
31
- const [error, setError] = useState<Error | null>(null);
32
-
33
- const upsert = useCallback(
34
- async (args: UpsertArgs): Promise<DocumentRecord> => {
35
- if (!runtime) {
36
- throw new Error('Notis runtime not available. Ensure NotisProvider is mounted.');
37
- }
38
-
39
- setLoading(true);
40
- setError(null);
41
-
42
- try {
43
- const result = await runtime.upsertDocument(args);
44
- return result.document;
45
- } catch (err) {
46
- const e = err instanceof Error ? err : new Error(String(err));
47
- setError(e);
48
- throw e;
49
- } finally {
50
- setLoading(false);
51
- }
52
- },
53
- [runtime],
54
- );
55
-
56
- return { upsert, loading, error };
57
- }
@@ -1,47 +0,0 @@
1
- /**
2
- * @notis/sdk - The Notis App SDK
3
- *
4
- * Public API for building Notis apps. Import hooks and the provider from
5
- * this entrypoint. For configuration, use `@notis/sdk/config`. For the
6
- * Vite config builder, use `@notis/sdk/vite`.
7
- */
8
-
9
- // Provider
10
- export { NotisProvider, useNotisRuntime } from './provider';
11
-
12
- // Hooks
13
- export { useNotis } from './hooks/useNotis';
14
- export { useDatabase } from './hooks/useDatabase';
15
- export { useDocument } from './hooks/useDocument';
16
- export { useUpsertDocument } from './hooks/useUpsertDocument';
17
- export { useTool } from './hooks/useTool';
18
- export { useTools } from './hooks/useTools';
19
- export { useCollectionItems } from './hooks/useCollectionItem';
20
- export { useNotisNavigation } from './hooks/useNotisNavigation';
21
- export { useBackend } from './hooks/useBackend';
22
- export { useAppState } from './hooks/useAppState';
23
-
24
- // Property extraction helpers
25
- export {
26
- extractText,
27
- extractSelect,
28
- extractDate,
29
- extractNumber,
30
- extractCheckbox,
31
- extractMultiSelect,
32
- extractRelation,
33
- docTitle,
34
- } from './helpers';
35
-
36
- // Types (re-exported for convenience)
37
- export type {
38
- AppDescriptor,
39
- CollectionItem,
40
- DatabaseDescriptor,
41
- DatabaseProperty,
42
- DocumentRecord,
43
- NotisRuntime,
44
- QueryFilter,
45
- RouteDescriptor,
46
- ToolDescriptor,
47
- } from './runtime';
@@ -1,44 +0,0 @@
1
- 'use client';
2
-
3
- import React, { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
4
- import type { NotisRuntime } from './runtime';
5
- import { getRuntime } from './runtime';
6
-
7
- const NotisContext = createContext<NotisRuntime | null>(null);
8
-
9
- /**
10
- * Provides the Notis runtime context to all child components. Place this in
11
- * your root layout so that hooks like useDatabase, useTool, etc. can access
12
- * the platform bridge.
13
- *
14
- * During `next dev` (no runtime injected), hooks return safe defaults (empty
15
- * arrays, null values). During `notis apps preview` and in the portal, the
16
- * runtime is fully functional.
17
- */
18
- export function NotisProvider({ children, runtime }: { children: ReactNode; runtime?: NotisRuntime | null }) {
19
- const [resolvedRuntime, setResolvedRuntime] = useState<NotisRuntime | null>(runtime ?? null);
20
-
21
- useEffect(() => {
22
- // If runtime was passed as a prop (portal component rendering), use it directly.
23
- // Otherwise fall back to window.__NOTIS_RUNTIME__ (local dev / preview).
24
- if (runtime !== undefined) {
25
- setResolvedRuntime(runtime);
26
- } else {
27
- setResolvedRuntime(getRuntime());
28
- }
29
- }, [runtime]);
30
-
31
- return (
32
- <NotisContext.Provider value={resolvedRuntime}>
33
- {children}
34
- </NotisContext.Provider>
35
- );
36
- }
37
-
38
- /**
39
- * Returns the raw NotisRuntime or null if not yet available.
40
- * Prefer the typed hooks (useDatabase, useTool, etc.) over this.
41
- */
42
- export function useNotisRuntime(): NotisRuntime | null {
43
- return useContext(NotisContext);
44
- }
@@ -1,159 +0,0 @@
1
- /**
2
- * NotisRuntime is the bridge between app code running in the browser and the
3
- * Notis platform. It is injected as `window.__NOTIS_RUNTIME__` into every app
4
- * page -- both in local preview (with mock implementations) and in the portal
5
- * (with real server-backed implementations).
6
- *
7
- * App code should never access `window.__NOTIS_RUNTIME__` directly. Instead,
8
- * use the hooks from `@notis/sdk` (useDatabase, useTool, etc.) which read
9
- * from the NotisProvider context.
10
- */
11
-
12
- // ---------------------------------------------------------------------------
13
- // Database types
14
- // ---------------------------------------------------------------------------
15
-
16
- export interface DatabaseProperty {
17
- name: string;
18
- type: 'title' | 'rich_text' | 'number' | 'checkbox' | 'date' | 'select' | 'multi_select' | 'status' | 'relation' | 'formula' | 'files';
19
- description?: string;
20
- options?: Array<{ name: string; id?: string }>;
21
- }
22
-
23
- export interface DatabaseDescriptor {
24
- slug: string;
25
- title: string;
26
- description?: string | null;
27
- icon?: string | null;
28
- properties: DatabaseProperty[];
29
- }
30
-
31
- export interface DocumentRecord {
32
- id: string;
33
- title: string;
34
- properties: Record<string, unknown>;
35
- icon?: string | null;
36
- databaseSlug?: string;
37
- }
38
-
39
- // ---------------------------------------------------------------------------
40
- // Tool types
41
- // ---------------------------------------------------------------------------
42
-
43
- export interface ToolDescriptor {
44
- name: string;
45
- description?: string;
46
- input_schema?: Record<string, unknown>;
47
- }
48
-
49
- // ---------------------------------------------------------------------------
50
- // Route types
51
- // ---------------------------------------------------------------------------
52
-
53
- export interface RouteDescriptor {
54
- slug: string;
55
- path: string;
56
- name: string;
57
- icon?: string | null;
58
- default?: boolean;
59
- collection?: {
60
- database: string;
61
- titleProperty: string;
62
- } | null;
63
- }
64
-
65
- export interface CollectionItem {
66
- id: string;
67
- title: string;
68
- icon?: string | null;
69
- }
70
-
71
- // ---------------------------------------------------------------------------
72
- // App descriptor
73
- // ---------------------------------------------------------------------------
74
-
75
- export interface AppDescriptor {
76
- id: string;
77
- name: string;
78
- icon?: string | null;
79
- description?: string | null;
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // Query types
84
- // ---------------------------------------------------------------------------
85
-
86
- export interface QueryFilter {
87
- filters?: Array<{
88
- property: string;
89
- operator: string;
90
- value: unknown;
91
- }>;
92
- sorts?: Array<{
93
- property: string;
94
- direction: 'asc' | 'desc';
95
- }>;
96
- page_size?: number;
97
- }
98
-
99
- // ---------------------------------------------------------------------------
100
- // NotisRuntime -- the window.__NOTIS_RUNTIME__ contract
101
- // ---------------------------------------------------------------------------
102
-
103
- export interface NotisRuntime {
104
- app: AppDescriptor;
105
- route: RouteDescriptor;
106
- databases: DatabaseDescriptor[];
107
-
108
- navigate?: (payload: { kind: string; [key: string]: unknown }) => void;
109
-
110
- listTools(): Promise<ToolDescriptor[]>;
111
- callTool(name: string, args?: Record<string, unknown>): Promise<unknown>;
112
-
113
- queryDatabase(args: {
114
- databaseSlug: string;
115
- query?: QueryFilter;
116
- offset?: number;
117
- }): Promise<{ documents: DocumentRecord[] }>;
118
-
119
- getDocument(args: {
120
- documentId: string;
121
- }): Promise<DocumentRecord>;
122
-
123
- upsertDocument(args: {
124
- databaseSlug: string;
125
- documentId?: string;
126
- title?: string;
127
- properties?: Record<string, unknown>;
128
- }): Promise<{ status: string; document: DocumentRecord }>;
129
-
130
- listCollectionItems(args?: {
131
- databaseSlug?: string;
132
- pageSize?: number;
133
- }): Promise<{ items: CollectionItem[] }>;
134
-
135
- request(path: string, options?: {
136
- method?: string;
137
- headers?: Record<string, string>;
138
- body?: unknown;
139
- }): Promise<unknown>;
140
- }
141
-
142
- // ---------------------------------------------------------------------------
143
- // Globals
144
- // ---------------------------------------------------------------------------
145
-
146
- declare global {
147
- interface Window {
148
- __NOTIS_RUNTIME__?: NotisRuntime;
149
- }
150
- }
151
-
152
- /**
153
- * Read the injected runtime from the window. Returns null during SSR or if the
154
- * runtime hasn't been injected yet (e.g. during `next dev` without preview).
155
- */
156
- export function getRuntime(): NotisRuntime | null {
157
- if (typeof window === 'undefined') return null;
158
- return window.__NOTIS_RUNTIME__ ?? null;
159
- }
@@ -1,123 +0,0 @@
1
- /**
2
- * Notis theme CSS variables.
3
- *
4
- * These match the portal's globals.css so that apps rendered inside the portal
5
- * iframe have identical styling. Import this in your root layout:
6
- *
7
- * import '@notis/sdk/styles.css';
8
- *
9
- * Then use Tailwind classes as normal -- shadcn components will pick up these
10
- * variables automatically.
11
- */
12
-
13
- @tailwind base;
14
- @tailwind components;
15
- @tailwind utilities;
16
-
17
- @layer base {
18
- :root {
19
- --background: 0 0% 100%;
20
- --foreground: 222.2 84% 4.9%;
21
- --card: 0 0% 100%;
22
- --card-foreground: 222.2 84% 4.9%;
23
- --popover: 0 0% 100%;
24
- --popover-foreground: 222.2 84% 4.9%;
25
- --primary: 222.2 47.4% 11.2%;
26
- --primary-foreground: 210 40% 98%;
27
- --secondary: 210 40% 96.1%;
28
- --secondary-foreground: 222.2 47.4% 11.2%;
29
- --muted: 210 40% 96.1%;
30
- --muted-foreground: 0 0% 46.9%;
31
- --accent: 210 40% 96.1%;
32
- --accent-foreground: 222.2 47.4% 11.2%;
33
- --destructive: 0 84.2% 60.2%;
34
- --destructive-foreground: 210 40% 98%;
35
- --border: 214.3 31.8% 91.4%;
36
- --input: 214.3 31.8% 91.4%;
37
- --ring: 222.2 84% 4.9%;
38
- --radius: 0.5rem;
39
- --sidebar-background: 0 0% 7.5%;
40
- --sidebar-foreground: 240 4.8% 95.9%;
41
- --sidebar-primary: 0 0% 7.5%;
42
- --sidebar-primary-foreground: 240 4.8% 95.9%;
43
- --sidebar-accent: 240 3.7% 15.9%;
44
- --sidebar-accent-foreground: 240 4.8% 95.9%;
45
- --sidebar-border: 0 0% 23.5%;
46
- --sidebar-ring: 217.2 91.2% 59.8%;
47
- --chart-1: 210 100% 49%;
48
- --chart-2: 173 58% 39%;
49
- --chart-3: 197 37% 24%;
50
- --chart-4: 43 74% 66%;
51
- --chart-5: 27 87% 67%;
52
- --code-block-background: #f6f6f6;
53
- --code-block-foreground: #27272a;
54
- --portal-page-max-width: 1100px;
55
- --portal-page-gutter-mobile: 1rem;
56
- --portal-page-gutter-desktop: 1rem;
57
- --portal-page-top-mobile: 1rem;
58
- --portal-page-top-desktop: 1.5rem;
59
- --portal-surface-pad-x-mobile: 1rem;
60
- --portal-surface-pad-x-desktop: 1.5rem;
61
- --portal-surface-pad-bottom: 1.5rem;
62
- }
63
-
64
- .dark {
65
- --background: 0 0% 13%;
66
- --foreground: 210 40% 98%;
67
- --card: 0 0% 13%;
68
- --card-foreground: 210 40% 98%;
69
- --popover: 0 0% 13%;
70
- --popover-foreground: 210 40% 98%;
71
- --primary: 210 40% 98%;
72
- --primary-foreground: 222.2 47.4% 11.2%;
73
- --secondary: 0 0% 18%;
74
- --secondary-foreground: 210 40% 98%;
75
- --muted: 0 0% 18%;
76
- --muted-foreground: 0 0% 65.1%;
77
- --accent: 0 0% 18%;
78
- --accent-foreground: 210 40% 98%;
79
- --destructive: 0 84.2% 60.2%;
80
- --destructive-foreground: 210 40% 98%;
81
- --border: 0 0% 23.5%;
82
- --input: 0 0% 23.5%;
83
- --ring: 212.7 26.8% 83.9%;
84
- --sidebar-background: 0 0% 7.5%;
85
- --sidebar-foreground: 240 4.8% 95.9%;
86
- --sidebar-primary: 224.3 76.3% 48%;
87
- --sidebar-primary-foreground: 0 0% 100%;
88
- --sidebar-accent: 240 3.7% 15.9%;
89
- --sidebar-accent-foreground: 240 4.8% 95.9%;
90
- --sidebar-border: 0 0% 23.5%;
91
- --sidebar-ring: 217.2 91.2% 59.8%;
92
- --chart-1: 210 100% 49%;
93
- --chart-2: 160 60% 45%;
94
- --chart-3: 30 80% 55%;
95
- --chart-4: 280 65% 60%;
96
- --chart-5: 340 75% 55%;
97
- --code-block-background: #1e1e1e;
98
- --code-block-foreground: #e4e4e7;
99
- }
100
- }
101
-
102
- @layer base {
103
- * {
104
- @apply border-border;
105
- }
106
- body {
107
- @apply bg-background text-foreground;
108
- }
109
- }
110
-
111
- @layer components {
112
- .notis-app-shell {
113
- @apply mx-auto w-full max-w-[var(--portal-page-max-width)] px-4 py-6 md:px-4 md:py-8;
114
- }
115
-
116
- .notis-app-surface {
117
- @apply rounded-2xl border border-border bg-card text-card-foreground shadow-sm;
118
- }
119
-
120
- .notis-app-section {
121
- @apply p-5 md:p-6;
122
- }
123
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * @notis/sdk/ui - Re-exported shadcn components for Notis apps.
3
- *
4
- * Apps include shadcn via their own `components.json` and `@/components/ui/*`
5
- * imports. This entrypoint is provided as a convenience for apps that want to
6
- * import directly from the SDK without setting up shadcn locally.
7
- *
8
- * For now, this is a placeholder. The scaffold template sets up shadcn
9
- * directly in the app project, so components come from `@/components/ui/*`.
10
- * This file can be expanded later to re-export a curated set of components
11
- * pre-themed for Notis.
12
- */
13
-
14
- // Placeholder -- apps use shadcn directly via their project's components/ui/
15
- export {};
@@ -1,54 +0,0 @@
1
- /**
2
- * Vite config builder for Notis apps.
3
- *
4
- * Usage:
5
- * ```ts
6
- * // vite.config.ts
7
- * import { notisViteConfig } from '@notis/sdk/vite';
8
- * import appConfig from './notis.config';
9
- * export default notisViteConfig(appConfig);
10
- * ```
11
- *
12
- * Produces a library-mode ES module bundle with React externalized.
13
- * Output: .notis/output/bundle/app.js + app.css
14
- */
15
-
16
- import type { NotisAppConfig } from './config';
17
-
18
- export function notisViteConfig(appConfig: NotisAppConfig) {
19
- return {
20
- plugins: [
21
- // @vitejs/plugin-react is added by the consumer's vite.config.ts
22
- // or auto-detected. We provide the config shape only.
23
- ],
24
- build: {
25
- lib: {
26
- entry: '.notis/_entry.tsx',
27
- formats: ['es'] as const,
28
- fileName: () => 'app.js',
29
- },
30
- rollupOptions: {
31
- external: ['react', 'react-dom', 'react/jsx-runtime'],
32
- output: {
33
- globals: {
34
- react: 'window.React',
35
- 'react-dom': 'window.ReactDOM',
36
- 'react/jsx-runtime': 'window.React',
37
- },
38
- assetFileNames: 'app[extname]',
39
- },
40
- },
41
- outDir: '.notis/output/bundle',
42
- emptyOutDir: true,
43
- cssCodeSplit: false,
44
- },
45
- resolve: {
46
- alias: {
47
- '@': process.cwd(),
48
- },
49
- },
50
- define: {
51
- 'process.env.NODE_ENV': JSON.stringify('production'),
52
- },
53
- };
54
- }
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "jsx": "react-jsx",
7
- "strict": true,
8
- "esModuleInterop": true,
9
- "skipLibCheck": true,
10
- "declaration": true,
11
- "outDir": "dist",
12
- "rootDir": "src"
13
- },
14
- "include": ["src"]
15
- }
@@ -1,8 +0,0 @@
1
- /** @type {import('postcss-load-config').Config} */
2
- const config = {
3
- plugins: {
4
- tailwindcss: {},
5
- },
6
- };
7
-
8
- export default config;
@@ -1,58 +0,0 @@
1
- import type { Config } from 'tailwindcss';
2
- import tailwindAnimate from 'tailwindcss-animate';
3
-
4
- const config: Config = {
5
- darkMode: ['class'],
6
- content: [
7
- './app/**/*.{ts,tsx}',
8
- './components/**/*.{ts,tsx}',
9
- './lib/**/*.{ts,tsx}',
10
- ],
11
- theme: {
12
- extend: {
13
- colors: {
14
- border: 'hsl(var(--border))',
15
- input: 'hsl(var(--input))',
16
- ring: 'hsl(var(--ring))',
17
- background: 'hsl(var(--background))',
18
- foreground: 'hsl(var(--foreground))',
19
- primary: {
20
- DEFAULT: 'hsl(var(--primary))',
21
- foreground: 'hsl(var(--primary-foreground))',
22
- },
23
- secondary: {
24
- DEFAULT: 'hsl(var(--secondary))',
25
- foreground: 'hsl(var(--secondary-foreground))',
26
- },
27
- destructive: {
28
- DEFAULT: 'hsl(var(--destructive))',
29
- foreground: 'hsl(var(--destructive-foreground))',
30
- },
31
- muted: {
32
- DEFAULT: 'hsl(var(--muted))',
33
- foreground: 'hsl(var(--muted-foreground))',
34
- },
35
- accent: {
36
- DEFAULT: 'hsl(var(--accent))',
37
- foreground: 'hsl(var(--accent-foreground))',
38
- },
39
- popover: {
40
- DEFAULT: 'hsl(var(--popover))',
41
- foreground: 'hsl(var(--popover-foreground))',
42
- },
43
- card: {
44
- DEFAULT: 'hsl(var(--card))',
45
- foreground: 'hsl(var(--card-foreground))',
46
- },
47
- },
48
- borderRadius: {
49
- lg: 'var(--radius)',
50
- md: 'calc(var(--radius) - 2px)',
51
- sm: 'calc(var(--radius) - 4px)',
52
- },
53
- },
54
- },
55
- plugins: [tailwindAnimate],
56
- };
57
-
58
- export default config;
@@ -1,22 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2017",
4
- "lib": ["dom", "dom.iterable", "esnext"],
5
- "allowJs": true,
6
- "skipLibCheck": true,
7
- "strict": true,
8
- "noEmit": true,
9
- "esModuleInterop": true,
10
- "module": "esnext",
11
- "moduleResolution": "bundler",
12
- "resolveJsonModule": true,
13
- "isolatedModules": true,
14
- "jsx": "react-jsx",
15
- "incremental": true,
16
- "paths": {
17
- "@/*": ["./*"]
18
- }
19
- },
20
- "include": ["**/*.ts", "**/*.tsx"],
21
- "exclude": ["node_modules"]
22
- }
@@ -1,10 +0,0 @@
1
- import { notisViteConfig } from '@notis/sdk/vite';
2
- import react from '@vitejs/plugin-react';
3
- import appConfig from './notis.config';
4
-
5
- const config = notisViteConfig(appConfig);
6
-
7
- export default {
8
- ...config,
9
- plugins: [react(), ...(config.plugins || [])],
10
- };