@notis_ai/cli 0.2.0-beta.16.1 → 0.2.0-beta.161.1
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 +435 -133
- package/bin/check-runtime.js +15 -0
- package/bin/notis.js +2 -0
- package/config/notis_app_boundary_rules.json +50 -0
- package/config/notis_app_design_rules.json +135 -0
- package/dist/agent-hooks/notis-agent-hook.mjs +19008 -0
- package/dist/base-skills/notis-apps/SKILL.md +70 -0
- package/dist/base-skills/notis-apps/references/architecture.md +164 -0
- package/dist/base-skills/notis-apps/references/context.md +81 -0
- package/dist/base-skills/notis-apps/references/design.md +165 -0
- package/dist/base-skills/notis-apps/references/reading.md +89 -0
- package/dist/base-skills/notis-apps/references/release.md +99 -0
- package/dist/base-skills/notis-apps/references/sdk.md +62 -0
- package/dist/base-skills/notis-apps/references/troubleshooting.md +23 -0
- package/dist/base-skills/notis-cli/SKILL.md +140 -0
- package/dist/base-skills/notis-cli/references/app-delivery.md +18 -0
- package/dist/base-skills/notis-cli/references/native-databases.md +20 -0
- package/dist/base-skills/notis-cli/references/tool-examples.md +56 -0
- package/dist/base-skills/notis-cli/references/troubleshooting.md +39 -0
- package/dist/base-skills/notis-query/SKILL.md +67 -0
- package/dist/base-skills/notis-query/references/database-discovery.md +59 -0
- package/dist/base-skills/notis-query/references/documents.md +50 -0
- package/dist/base-skills/notis-query/references/query.md +543 -0
- package/dist/skill-sync/index.js +1626 -0
- package/dist/skill-sync/index.js.map +7 -0
- package/dist/skill-sync-worker.mjs +2990 -0
- package/package.json +18 -7
- package/skills/notis-apps/cli.md +313 -0
- package/skills/notis-cli/AGENT_INSTRUCTIONS.md +39 -0
- package/skills/notis-onboarding/BRIEF.md +129 -0
- package/skills/notis-query/cli.md +39 -0
- package/src/agent-hook-entry.js +5 -0
- package/src/cli.js +294 -25
- package/src/command-specs/agents.js +392 -0
- package/src/command-specs/apps.js +1470 -202
- package/src/command-specs/auth.js +114 -137
- package/src/command-specs/diagnostics.js +729 -0
- package/src/command-specs/handover.js +374 -0
- package/src/command-specs/helpers.js +84 -82
- package/src/command-specs/index.js +25 -6
- package/src/command-specs/meta.js +150 -18
- package/src/command-specs/onboarding.js +290 -0
- package/src/command-specs/profile.js +358 -0
- package/src/command-specs/reports.js +86 -0
- package/src/command-specs/skills.js +75 -0
- package/src/command-specs/smoke.js +386 -0
- package/src/command-specs/tools.js +455 -139
- package/src/runtime/agent-browser.js +632 -0
- package/src/runtime/agent-memory-state.js +126 -0
- package/src/runtime/agent-setup.js +383 -0
- package/src/runtime/app-boundary-validator.js +404 -0
- package/src/runtime/app-changelog.js +79 -0
- package/src/runtime/app-platform.js +2633 -210
- package/src/runtime/app-registry-scaffolds.js +367 -0
- package/src/runtime/app-test-server.js +292 -0
- package/src/runtime/assets/store-screenshot-dark.png +0 -0
- package/src/runtime/auth-recovery.js +110 -0
- package/src/runtime/base-skills.d.ts +20 -0
- package/src/runtime/base-skills.js +167 -0
- package/src/runtime/channel.js +133 -0
- package/src/runtime/delegated-context.js +68 -0
- package/src/runtime/errors.js +1 -0
- package/src/runtime/git.js +233 -0
- package/src/runtime/login-listener.js +15 -0
- package/src/runtime/oauth.js +2622 -0
- package/src/runtime/output.js +37 -5
- package/src/runtime/ports.js +31 -0
- package/src/runtime/profiles.js +906 -55
- package/src/runtime/skill-sync/cloud-client.ts +99 -0
- package/src/runtime/skill-sync/index.ts +697 -0
- package/src/runtime/skill-sync/local-scanner.ts +1046 -0
- package/src/runtime/skill-sync/symlink-manager.ts +433 -0
- package/src/runtime/skill-sync/sync-plan.ts +22 -0
- package/src/runtime/skill-sync/types.ts +110 -0
- package/src/runtime/skill-sync/write-cloud-skill.ts +50 -0
- package/src/runtime/skill-sync-service.js +109 -0
- package/src/runtime/store-screenshot.js +143 -0
- package/src/runtime/sync-skills.d.ts +37 -0
- package/src/runtime/sync-skills.js +231 -0
- package/src/runtime/telemetry.js +92 -0
- package/src/runtime/transport.js +324 -45
- package/src/skill-sync-worker-entry.js +2 -0
- package/src/skill-sync-worker.js +50 -0
- package/template/.harness/index.html.tmpl +430 -0
- package/template/CHANGELOG.md +5 -0
- package/template/app/globals.css +28 -3
- package/template/app/layout.tsx +6 -3
- package/template/app/page.tsx +49 -42
- package/template/components/page-heading.tsx +23 -0
- package/template/components/ui/badge.tsx +7 -4
- package/template/components/ui/button.tsx +1 -1
- package/template/components/ui/card.tsx +24 -11
- package/template/components/ui/native-select.tsx +24 -0
- package/template/notis.config.ts +24 -6
- package/template/package-lock.json +3642 -0
- package/template/package.json +19 -16
- package/template/packages/{notis-sdk → sdk}/package.json +14 -4
- package/template/packages/sdk/src/agentContext.ts +36 -0
- package/template/packages/sdk/src/components/DocumentEditor.tsx +103 -0
- package/template/packages/sdk/src/components/Markdown.tsx +60 -0
- package/template/packages/sdk/src/components/MarkdownEditor.tsx +121 -0
- package/template/packages/sdk/src/components/MultiSelectActionBar.tsx +285 -0
- package/template/packages/sdk/src/components/MultiSelectCheckbox.tsx +97 -0
- package/template/packages/sdk/src/components/MultiSelectDragOverlay.tsx +39 -0
- package/template/packages/sdk/src/components/NotisCommentBoundary.tsx +172 -0
- package/template/packages/sdk/src/components/NotisSelectionBoundary.tsx +59 -0
- package/template/packages/sdk/src/components/ShortcutHints.tsx +56 -0
- package/template/packages/sdk/src/components/Skeleton.tsx +24 -0
- package/template/packages/sdk/src/config.ts +257 -0
- package/template/packages/sdk/src/documents.ts +256 -0
- package/template/packages/sdk/src/hooks/useActiveResource.ts +19 -0
- package/template/packages/sdk/src/hooks/useAgentContext.ts +23 -0
- package/template/packages/sdk/src/hooks/useCloudComputer.ts +64 -0
- package/template/packages/sdk/src/hooks/useCollectionInteractions.ts +836 -0
- package/template/packages/sdk/src/hooks/useDatabaseSchema.ts +49 -0
- package/template/packages/sdk/src/hooks/useDatabaseSubscription.ts +76 -0
- package/template/packages/sdk/src/hooks/useDocument.ts +43 -0
- package/template/packages/sdk/src/hooks/useDocuments.ts +84 -0
- package/template/packages/sdk/src/hooks/useHandover.ts +78 -0
- package/template/packages/sdk/src/hooks/useLongPressSelection.ts +79 -0
- package/template/packages/sdk/src/hooks/useMultiSelect.ts +95 -0
- package/template/packages/{notis-sdk → sdk}/src/hooks/useNotis.ts +10 -4
- package/template/packages/{notis-sdk → sdk}/src/hooks/useNotisNavigation.ts +11 -8
- package/template/packages/sdk/src/hooks/useQuery.ts +71 -0
- package/template/packages/sdk/src/hooks/useTool.ts +65 -0
- package/template/packages/sdk/src/hooks/useToolQuery.ts +12 -0
- package/template/packages/sdk/src/hooks/useTopBarSearch.ts +81 -0
- package/template/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/template/packages/sdk/src/index.ts +161 -0
- package/template/packages/sdk/src/interactions/actions.ts +59 -0
- package/template/packages/sdk/src/interactions/shortcuts.tsx +694 -0
- package/template/packages/sdk/src/interactions/visibility.ts +13 -0
- package/template/packages/sdk/src/interactions.ts +45 -0
- package/template/packages/sdk/src/provider.tsx +44 -0
- package/template/packages/sdk/src/queryCache.ts +170 -0
- package/template/packages/sdk/src/runtime.ts +451 -0
- package/template/packages/sdk/src/styles.css +247 -0
- package/template/packages/sdk/src/tailwind.ts +66 -0
- package/template/packages/sdk/src/vite.ts +73 -0
- package/template/packages/{notis-sdk → sdk}/tsconfig.json +1 -0
- package/template/postcss.config.mjs +1 -1
- package/template/tailwind.config.ts +1 -6
- package/template/tsconfig.json +1 -0
- package/src/command-specs/db.js +0 -163
- package/src/runtime/app-preview-server.js +0 -312
- package/template/packages/notis-sdk/src/config.ts +0 -48
- package/template/packages/notis-sdk/src/helpers.ts +0 -131
- package/template/packages/notis-sdk/src/hooks/useAppState.ts +0 -50
- package/template/packages/notis-sdk/src/hooks/useCollectionItem.ts +0 -58
- package/template/packages/notis-sdk/src/hooks/useDatabase.ts +0 -87
- package/template/packages/notis-sdk/src/hooks/useDocument.ts +0 -61
- package/template/packages/notis-sdk/src/hooks/useTool.ts +0 -49
- package/template/packages/notis-sdk/src/hooks/useUpsertDocument.ts +0 -57
- package/template/packages/notis-sdk/src/index.ts +0 -47
- package/template/packages/notis-sdk/src/provider.tsx +0 -44
- package/template/packages/notis-sdk/src/runtime.ts +0 -159
- package/template/packages/notis-sdk/src/styles.css +0 -123
- package/template/packages/notis-sdk/src/vite.ts +0 -54
- /package/template/packages/{notis-sdk → sdk}/src/hooks/useBackend.ts +0 -0
- /package/template/packages/{notis-sdk → sdk}/src/hooks/useTools.ts +0 -0
- /package/template/packages/{notis-sdk → sdk}/src/ui.ts +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration utilities for notis.config.ts.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* ```ts
|
|
6
|
-
* // notis.config.ts
|
|
7
|
-
* import { defineNotisApp } from '@notis/sdk/config';
|
|
8
|
-
*
|
|
9
|
-
* export default defineNotisApp({
|
|
10
|
-
* name: 'My App',
|
|
11
|
-
* description: 'Does things',
|
|
12
|
-
* icon: 'lucide:layout-dashboard',
|
|
13
|
-
* databases: ['tasks'],
|
|
14
|
-
* routes: [...],
|
|
15
|
-
* tools: [...],
|
|
16
|
-
* });
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
export interface NotisRouteConfig {
|
|
21
|
-
path: string;
|
|
22
|
-
name: string;
|
|
23
|
-
icon?: string;
|
|
24
|
-
default?: boolean;
|
|
25
|
-
exportName?: string;
|
|
26
|
-
collection?: {
|
|
27
|
-
database: string;
|
|
28
|
-
titleProperty: string;
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface NotisAppConfig {
|
|
33
|
-
name: string;
|
|
34
|
-
description?: string;
|
|
35
|
-
icon?: string;
|
|
36
|
-
databases?: string[];
|
|
37
|
-
routes?: NotisRouteConfig[];
|
|
38
|
-
tools?: string[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Identity function that provides type checking and autocomplete for the
|
|
43
|
-
* Notis app configuration. The returned object is read at build time by
|
|
44
|
-
* `notis apps build` to generate the manifest.
|
|
45
|
-
*/
|
|
46
|
-
export function defineNotisApp(config: NotisAppConfig): NotisAppConfig {
|
|
47
|
-
return config;
|
|
48
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Property extraction helpers for Notis DocumentRecord properties.
|
|
3
|
-
*
|
|
4
|
-
* Document properties come back in Notion-style nested shapes. These helpers
|
|
5
|
-
* normalize them into simple JS values regardless of the shape.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { DocumentRecord } from './runtime';
|
|
9
|
-
|
|
10
|
-
type Obj = Record<string, unknown>;
|
|
11
|
-
|
|
12
|
-
/** Extract a string from a title, rich_text, or plain text property. */
|
|
13
|
-
export function extractText(val: unknown): string {
|
|
14
|
-
if (typeof val === 'string') return val;
|
|
15
|
-
if (val && typeof val === 'object') {
|
|
16
|
-
const obj = val as Obj;
|
|
17
|
-
if (typeof obj.content === 'string') return obj.content;
|
|
18
|
-
if (typeof obj.plain_text === 'string') return obj.plain_text;
|
|
19
|
-
if (Array.isArray(obj.title)) {
|
|
20
|
-
return obj.title.map((t: Obj) => extractText(t?.text || t)).join('');
|
|
21
|
-
}
|
|
22
|
-
if (Array.isArray(obj.rich_text)) {
|
|
23
|
-
return obj.rich_text.map((t: Obj) => extractText(t?.text || t)).join('');
|
|
24
|
-
}
|
|
25
|
-
if (obj.text) return extractText(obj.text);
|
|
26
|
-
}
|
|
27
|
-
return '';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Extract a string from a select or status property. */
|
|
31
|
-
export function extractSelect(val: unknown): string {
|
|
32
|
-
if (typeof val === 'string') return val;
|
|
33
|
-
if (val && typeof val === 'object') {
|
|
34
|
-
const obj = val as Obj;
|
|
35
|
-
if (obj.select && typeof obj.select === 'object') {
|
|
36
|
-
return (obj.select as Obj).name as string || '';
|
|
37
|
-
}
|
|
38
|
-
if (obj.status && typeof obj.status === 'object') {
|
|
39
|
-
return (obj.status as Obj).name as string || '';
|
|
40
|
-
}
|
|
41
|
-
if (typeof obj.name === 'string') return obj.name;
|
|
42
|
-
}
|
|
43
|
-
return '';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Extract a date string from a date property. */
|
|
47
|
-
export function extractDate(val: unknown): string {
|
|
48
|
-
if (typeof val === 'string') return val;
|
|
49
|
-
if (val && typeof val === 'object') {
|
|
50
|
-
const obj = val as Obj;
|
|
51
|
-
if (obj.date && typeof obj.date === 'object') {
|
|
52
|
-
return (obj.date as Obj).start as string || '';
|
|
53
|
-
}
|
|
54
|
-
if (typeof obj.start === 'string') return obj.start;
|
|
55
|
-
}
|
|
56
|
-
return '';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** Extract a number from a number property. */
|
|
60
|
-
export function extractNumber(val: unknown): number | null {
|
|
61
|
-
if (typeof val === 'number') return val;
|
|
62
|
-
if (val && typeof val === 'object') {
|
|
63
|
-
const obj = val as Obj;
|
|
64
|
-
if (typeof obj.number === 'number') return obj.number;
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Extract a boolean from a checkbox property. */
|
|
70
|
-
export function extractCheckbox(val: unknown): boolean {
|
|
71
|
-
if (typeof val === 'boolean') return val;
|
|
72
|
-
if (val && typeof val === 'object') {
|
|
73
|
-
const obj = val as Obj;
|
|
74
|
-
if (typeof obj.checkbox === 'boolean') return obj.checkbox;
|
|
75
|
-
}
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Extract multi-select values as a string array. */
|
|
80
|
-
export function extractMultiSelect(val: unknown): string[] {
|
|
81
|
-
if (Array.isArray(val)) {
|
|
82
|
-
return val
|
|
83
|
-
.map((v) => {
|
|
84
|
-
if (typeof v === 'string') return v;
|
|
85
|
-
if (v && typeof v === 'object' && typeof (v as Obj).name === 'string') return (v as Obj).name as string;
|
|
86
|
-
return '';
|
|
87
|
-
})
|
|
88
|
-
.filter(Boolean);
|
|
89
|
-
}
|
|
90
|
-
if (val && typeof val === 'object') {
|
|
91
|
-
const obj = val as Obj;
|
|
92
|
-
if (Array.isArray(obj.multi_select)) return extractMultiSelect(obj.multi_select);
|
|
93
|
-
}
|
|
94
|
-
if (typeof val === 'string' && val) return [val];
|
|
95
|
-
return [];
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Extract relation IDs from a relation property. */
|
|
99
|
-
export function extractRelation(val: unknown): string[] {
|
|
100
|
-
if (Array.isArray(val)) {
|
|
101
|
-
return val
|
|
102
|
-
.map((v) => {
|
|
103
|
-
if (typeof v === 'string') return v;
|
|
104
|
-
if (v && typeof v === 'object' && typeof (v as Obj).id === 'string') return (v as Obj).id as string;
|
|
105
|
-
return '';
|
|
106
|
-
})
|
|
107
|
-
.filter(Boolean);
|
|
108
|
-
}
|
|
109
|
-
if (val && typeof val === 'object') {
|
|
110
|
-
const obj = val as Obj;
|
|
111
|
-
if (Array.isArray(obj.relation)) return extractRelation(obj.relation);
|
|
112
|
-
}
|
|
113
|
-
if (typeof val === 'string' && val) return [val];
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Extract display title from a document. Falls back through several property
|
|
119
|
-
* names and shapes to find a human-readable title.
|
|
120
|
-
*/
|
|
121
|
-
export function docTitle(doc: DocumentRecord): string {
|
|
122
|
-
const t = doc.title;
|
|
123
|
-
if (t && !/^[0-9a-f]{8}-[0-9a-f]{4}/.test(t)) return t;
|
|
124
|
-
const p = doc.properties || {};
|
|
125
|
-
const name = p.Name ?? p.name ?? p.Title ?? p.title;
|
|
126
|
-
if (name) {
|
|
127
|
-
const extracted = extractText(name);
|
|
128
|
-
if (extracted) return extracted;
|
|
129
|
-
}
|
|
130
|
-
return t || 'Untitled';
|
|
131
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useCallback, useState } from 'react';
|
|
4
|
-
import { useNotisRuntime } from '../provider';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Persist app-level state per user per app using localStorage.
|
|
8
|
-
*
|
|
9
|
-
* ```tsx
|
|
10
|
-
* const [order, setOrder] = useAppState<string[]>('task-order', []);
|
|
11
|
-
* ```
|
|
12
|
-
*
|
|
13
|
-
* State is scoped by `app.id` so different apps don't collide.
|
|
14
|
-
* Falls back to defaultValue when localStorage is unavailable.
|
|
15
|
-
*/
|
|
16
|
-
export function useAppState<T>(key: string, defaultValue: T): [T, (value: T | ((prev: T) => T)) => void] {
|
|
17
|
-
const runtime = useNotisRuntime();
|
|
18
|
-
const appId = runtime?.app?.id || '_unknown';
|
|
19
|
-
const storageKey = `notis-app-state:${appId}:${key}`;
|
|
20
|
-
|
|
21
|
-
const [value, setValueInternal] = useState<T>(() => {
|
|
22
|
-
if (typeof window === 'undefined') return defaultValue;
|
|
23
|
-
try {
|
|
24
|
-
const stored = localStorage.getItem(storageKey);
|
|
25
|
-
if (stored !== null) return JSON.parse(stored) as T;
|
|
26
|
-
} catch {
|
|
27
|
-
// Ignore parse errors or storage unavailable
|
|
28
|
-
}
|
|
29
|
-
return defaultValue;
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const setValue = useCallback(
|
|
33
|
-
(newValue: T | ((prev: T) => T)) => {
|
|
34
|
-
setValueInternal((prev) => {
|
|
35
|
-
const resolved = typeof newValue === 'function'
|
|
36
|
-
? (newValue as (prev: T) => T)(prev)
|
|
37
|
-
: newValue;
|
|
38
|
-
try {
|
|
39
|
-
localStorage.setItem(storageKey, JSON.stringify(resolved));
|
|
40
|
-
} catch {
|
|
41
|
-
// Ignore quota errors
|
|
42
|
-
}
|
|
43
|
-
return resolved;
|
|
44
|
-
});
|
|
45
|
-
},
|
|
46
|
-
[storageKey],
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
return [value, setValue];
|
|
50
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
import { useNotisRuntime } from '../provider';
|
|
5
|
-
import type { CollectionItem } from '../runtime';
|
|
6
|
-
|
|
7
|
-
interface UseCollectionResult {
|
|
8
|
-
/** Items in the collection (from the bound database). */
|
|
9
|
-
items: CollectionItem[];
|
|
10
|
-
loading: boolean;
|
|
11
|
-
error: Error | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* List collection items for the current route. Only meaningful on routes
|
|
16
|
-
* that have a `collection` binding in `notis.config.ts`.
|
|
17
|
-
*
|
|
18
|
-
* ```tsx
|
|
19
|
-
* const { items, loading } = useCollectionItems();
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export function useCollectionItems(): UseCollectionResult {
|
|
23
|
-
const runtime = useNotisRuntime();
|
|
24
|
-
const [items, setItems] = useState<CollectionItem[]>([]);
|
|
25
|
-
const [loading, setLoading] = useState(true);
|
|
26
|
-
const [error, setError] = useState<Error | null>(null);
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
if (!runtime) {
|
|
30
|
-
setLoading(false);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let cancelled = false;
|
|
35
|
-
setLoading(true);
|
|
36
|
-
|
|
37
|
-
runtime
|
|
38
|
-
.listCollectionItems()
|
|
39
|
-
.then((result) => {
|
|
40
|
-
if (!cancelled) {
|
|
41
|
-
setItems(result.items);
|
|
42
|
-
setLoading(false);
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
.catch((err) => {
|
|
46
|
-
if (!cancelled) {
|
|
47
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
48
|
-
setLoading(false);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return () => {
|
|
53
|
-
cancelled = true;
|
|
54
|
-
};
|
|
55
|
-
}, [runtime]);
|
|
56
|
-
|
|
57
|
-
return { items, loading, error };
|
|
58
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
-
import { useNotisRuntime } from '../provider';
|
|
5
|
-
import type { DocumentRecord, QueryFilter } from '../runtime';
|
|
6
|
-
|
|
7
|
-
interface UseDatabaseOptions {
|
|
8
|
-
filter?: QueryFilter;
|
|
9
|
-
pageSize?: number;
|
|
10
|
-
offset?: number;
|
|
11
|
-
/** Set to false to skip the initial fetch. */
|
|
12
|
-
enabled?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface UseDatabaseResult {
|
|
16
|
-
documents: DocumentRecord[];
|
|
17
|
-
loading: boolean;
|
|
18
|
-
error: Error | null;
|
|
19
|
-
refetch: () => void;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Query documents from a Notis database owned by this app.
|
|
24
|
-
*
|
|
25
|
-
* ```tsx
|
|
26
|
-
* const { documents, loading } = useDatabase('transactions', {
|
|
27
|
-
* filter: { sorts: [{ property: 'date', direction: 'desc' }] },
|
|
28
|
-
* pageSize: 20,
|
|
29
|
-
* });
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export function useDatabase(
|
|
33
|
-
databaseSlug: string,
|
|
34
|
-
options: UseDatabaseOptions = {},
|
|
35
|
-
): UseDatabaseResult {
|
|
36
|
-
const runtime = useNotisRuntime();
|
|
37
|
-
const [documents, setDocuments] = useState<DocumentRecord[]>([]);
|
|
38
|
-
const [loading, setLoading] = useState(true);
|
|
39
|
-
const [error, setError] = useState<Error | null>(null);
|
|
40
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
41
|
-
|
|
42
|
-
const enabled = options.enabled !== false;
|
|
43
|
-
|
|
44
|
-
const refetch = useCallback(() => {
|
|
45
|
-
setFetchKey((k) => k + 1);
|
|
46
|
-
}, []);
|
|
47
|
-
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
if (!runtime || !enabled) {
|
|
50
|
-
setLoading(false);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let cancelled = false;
|
|
55
|
-
setLoading(true);
|
|
56
|
-
setError(null);
|
|
57
|
-
|
|
58
|
-
runtime
|
|
59
|
-
.queryDatabase({
|
|
60
|
-
databaseSlug,
|
|
61
|
-
query: {
|
|
62
|
-
...options.filter,
|
|
63
|
-
page_size: options.pageSize,
|
|
64
|
-
},
|
|
65
|
-
offset: options.offset,
|
|
66
|
-
})
|
|
67
|
-
.then((result) => {
|
|
68
|
-
if (!cancelled) {
|
|
69
|
-
setDocuments(result.documents);
|
|
70
|
-
setLoading(false);
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
.catch((err) => {
|
|
74
|
-
if (!cancelled) {
|
|
75
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
76
|
-
setLoading(false);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
return () => {
|
|
81
|
-
cancelled = true;
|
|
82
|
-
};
|
|
83
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
84
|
-
}, [runtime, databaseSlug, fetchKey, enabled]);
|
|
85
|
-
|
|
86
|
-
return { documents, loading, error, refetch };
|
|
87
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
-
import { useNotisRuntime } from '../provider';
|
|
5
|
-
import type { DocumentRecord } from '../runtime';
|
|
6
|
-
|
|
7
|
-
interface UseDocumentResult {
|
|
8
|
-
document: DocumentRecord | null;
|
|
9
|
-
loading: boolean;
|
|
10
|
-
error: Error | null;
|
|
11
|
-
refetch: () => void;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Fetch a single document by ID.
|
|
16
|
-
*
|
|
17
|
-
* ```tsx
|
|
18
|
-
* const { document, loading } = useDocument(documentId);
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export function useDocument(documentId: string | null | undefined): UseDocumentResult {
|
|
22
|
-
const runtime = useNotisRuntime();
|
|
23
|
-
const [document, setDocument] = useState<DocumentRecord | null>(null);
|
|
24
|
-
const [loading, setLoading] = useState(true);
|
|
25
|
-
const [error, setError] = useState<Error | null>(null);
|
|
26
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
27
|
-
|
|
28
|
-
const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (!runtime || !documentId) {
|
|
32
|
-
setLoading(false);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let cancelled = false;
|
|
37
|
-
setLoading(true);
|
|
38
|
-
setError(null);
|
|
39
|
-
|
|
40
|
-
runtime
|
|
41
|
-
.getDocument({ documentId })
|
|
42
|
-
.then((result) => {
|
|
43
|
-
if (!cancelled) {
|
|
44
|
-
setDocument(result);
|
|
45
|
-
setLoading(false);
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
.catch((err) => {
|
|
49
|
-
if (!cancelled) {
|
|
50
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
51
|
-
setLoading(false);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return () => {
|
|
56
|
-
cancelled = true;
|
|
57
|
-
};
|
|
58
|
-
}, [runtime, documentId, fetchKey]);
|
|
59
|
-
|
|
60
|
-
return { document, loading, error, refetch };
|
|
61
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useCallback, useState } from 'react';
|
|
4
|
-
import { useNotisRuntime } from '../provider';
|
|
5
|
-
|
|
6
|
-
interface UseToolResult {
|
|
7
|
-
call: (args?: Record<string, unknown>) => Promise<unknown>;
|
|
8
|
-
loading: boolean;
|
|
9
|
-
error: Error | null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Call a specific Notis tool by name.
|
|
14
|
-
*
|
|
15
|
-
* ```tsx
|
|
16
|
-
* const { call, loading } = useTool('notis_web_search');
|
|
17
|
-
* const result = await call({ query: 'latest news' });
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export function useTool(toolName: string): UseToolResult {
|
|
21
|
-
const runtime = useNotisRuntime();
|
|
22
|
-
const [loading, setLoading] = useState(false);
|
|
23
|
-
const [error, setError] = useState<Error | null>(null);
|
|
24
|
-
|
|
25
|
-
const call = useCallback(
|
|
26
|
-
async (args?: Record<string, unknown>): Promise<unknown> => {
|
|
27
|
-
if (!runtime) {
|
|
28
|
-
throw new Error('Notis runtime not available. Ensure NotisProvider is mounted.');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
setLoading(true);
|
|
32
|
-
setError(null);
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const result = await runtime.callTool(toolName, args);
|
|
36
|
-
return result;
|
|
37
|
-
} catch (err) {
|
|
38
|
-
const e = err instanceof Error ? err : new Error(String(err));
|
|
39
|
-
setError(e);
|
|
40
|
-
throw e;
|
|
41
|
-
} finally {
|
|
42
|
-
setLoading(false);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
[runtime, toolName],
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
return { call, loading, error };
|
|
49
|
-
}
|
|
@@ -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
|
-
}
|