@sutrata/editor 0.1.0 → 0.1.2
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 +87 -0
- package/dist/ai/generated-providers.json +1 -1
- package/package.json +36 -9
- package/scripts/copy-assets.mjs +0 -16
- package/scripts/generate-providers.mjs +0 -127
- package/src/ai/OnboardingDialog.tsx +0 -390
- package/src/ai/VoiceConfirmDialog.tsx +0 -137
- package/src/ai/VoiceToolbar.tsx +0 -321
- package/src/ai/ai-client.ts +0 -596
- package/src/ai/commands.ts +0 -164
- package/src/ai/generated-providers.json +0 -3696
- package/src/ai/prompts.ts +0 -62
- package/src/ai/voice-service.ts +0 -96
- package/src/autocomplete/AutocompletePlugin.ts +0 -21
- package/src/autocomplete/suggestions.ts +0 -147
- package/src/context/DocumentContext.tsx +0 -648
- package/src/desktop-api.d.ts +0 -40
- package/src/editor/EditorView.tsx +0 -82
- package/src/editor/SelectionMenu.tsx +0 -152
- package/src/editor/attr-pencil-plugin.ts +0 -172
- package/src/editor/character-decoration-plugin.ts +0 -104
- package/src/editor/editor-bus.ts +0 -51
- package/src/editor/find-highlight-plugin.ts +0 -68
- package/src/editor/frontmatter-field-view.ts +0 -52
- package/src/editor/frontmatter-field.ts +0 -115
- package/src/editor/grapheme-cursor.ts +0 -99
- package/src/editor/ime-plugin.ts +0 -85
- package/src/editor/insert-helper.ts +0 -43
- package/src/editor/keymap.ts +0 -124
- package/src/editor/language-class-plugin.ts +0 -91
- package/src/editor/plugins.ts +0 -26
- package/src/editor/prosemirror-to-sutra.ts +0 -192
- package/src/editor/scene-heading-view.ts +0 -147
- package/src/editor/schema.ts +0 -156
- package/src/editor/sutra-to-prosemirror.ts +0 -156
- package/src/extensions/storage-adapter.ts +0 -65
- package/src/extensions/types.ts +0 -60
- package/src/file/docx-exporter.ts +0 -585
- package/src/file/docx-importer.ts +0 -313
- package/src/file/print-paginator.ts +0 -301
- package/src/file/templates.ts +0 -73
- package/src/file/workflow-reports.ts +0 -820
- package/src/findreplace/FindReplace.tsx +0 -242
- package/src/findreplace/find-engine.ts +0 -97
- package/src/findreplace/scroll-to-match.ts +0 -89
- package/src/fonts/tofu-detect.ts +0 -53
- package/src/i18n/LanguageContext.tsx +0 -207
- package/src/i18n/language-detect.ts +0 -73
- package/src/i18n/useTranslation.tsx +0 -74
- package/src/index.ts +0 -27
- package/src/locales/bn.json +0 -143
- package/src/locales/en.json +0 -143
- package/src/locales/gu.json +0 -143
- package/src/locales/hi.json +0 -143
- package/src/locales/kn.json +0 -143
- package/src/locales/ml.json +0 -143
- package/src/locales/mr.json +0 -143
- package/src/locales/or.json +0 -143
- package/src/locales/pa.json +0 -143
- package/src/locales/si.json +0 -143
- package/src/locales/ta.json +0 -143
- package/src/locales/te.json +0 -143
- package/src/navigator/SceneNavigator.tsx +0 -844
- package/src/navigator/StatisticsDialog.tsx +0 -249
- package/src/navigator/scene-list.ts +0 -84
- package/src/settings/SettingsDialog.tsx +0 -303
- package/src/shell/AppBar.tsx +0 -354
- package/src/shell/AppShell.tsx +0 -71
- package/src/shell/ConfirmDialog.tsx +0 -71
- package/src/shell/ElementToolbar.tsx +0 -175
- package/src/shell/LanguageStatus.tsx +0 -101
- package/src/shell/StatusBar.tsx +0 -135
- package/src/shell/SutrataLogo.tsx +0 -89
- package/src/shell/Toast.tsx +0 -46
- package/src/shell/ToolbarButton.tsx +0 -30
- package/src/shell/VersionHistory.tsx +0 -212
- package/src/shell/Watermark.tsx +0 -9
- package/src/shell/fonts/fonts.css +0 -1133
- package/src/shell/icons.tsx +0 -335
- package/src/shell/toolbar-actions.ts +0 -59
- package/src/source/SourceView.tsx +0 -111
- package/src/source/find-highlight-source.ts +0 -57
- package/src/source/sutra-lang.ts +0 -121
- package/src/spellcheck/dictionaries.ts +0 -21
- package/src/spellcheck/hunspell.ts +0 -110
- package/src/spellcheck/spellcheck-plugin.ts +0 -83
- package/src/styles/StyleDialog.tsx +0 -148
- package/src/styles/builtin-styles.ts +0 -139
- package/src/styles/css-adapter.ts +0 -76
- package/src/styles/docx-adapter.ts +0 -109
- package/src/styles/embed-fonts.ts +0 -81
- package/src/styles/pagination.ts +0 -27
- package/src/styles/print-adapter.ts +0 -288
- package/src/styles/registry.ts +0 -20
- package/src/styles/screenplay.css +0 -3006
- package/src/styles/script-ranges.ts +0 -17
- package/src/styles/types.ts +0 -104
- package/src/styles/validate.ts +0 -114
- package/src/templates/templates.ts +0 -194
- package/src/titlepage/ExportDialog.tsx +0 -494
- package/src/titlepage/TitlePageDialog.tsx +0 -312
- package/src/titlepage/frontmatter-form.ts +0 -280
- package/src/titlepage/languages.ts +0 -37
- package/src/types.ts +0 -7
- package/tests/AppBar.test.tsx +0 -35
- package/tests/AppShell.test.tsx +0 -22
- package/tests/ElementToolbar.test.tsx +0 -36
- package/tests/LanguageStatus.test.tsx +0 -129
- package/tests/SelectionMenu.test.tsx +0 -71
- package/tests/ToolbarButton.test.tsx +0 -24
- package/tests/ai-onboarding.test.ts +0 -102
- package/tests/ai-status.test.tsx +0 -72
- package/tests/ai-structured.test.ts +0 -94
- package/tests/autocomplete/AutocompletePlugin.test.ts +0 -20
- package/tests/autocomplete/suggestions.test.ts +0 -106
- package/tests/document-context.test.tsx +0 -565
- package/tests/docx-importer.test.ts +0 -160
- package/tests/editor/character-decoration-plugin.test.ts +0 -101
- package/tests/editor/character-extension.test.ts +0 -44
- package/tests/editor/grapheme-cursor.test.ts +0 -118
- package/tests/editor/ime-plugin.test.ts +0 -72
- package/tests/editor/inline-note-bridge.test.ts +0 -32
- package/tests/editor/language-class-plugin.test.ts +0 -265
- package/tests/editor/title-page.test.ts +0 -124
- package/tests/embed-fonts.test.ts +0 -17
- package/tests/exporters.test.ts +0 -365
- package/tests/findreplace/FindReplace.test.tsx +0 -391
- package/tests/findreplace/find-engine.test.ts +0 -86
- package/tests/findreplace/scroll-to-match.test.ts +0 -50
- package/tests/fonts/tofu-detect.test.ts +0 -122
- package/tests/i18n/LanguageContext.test.tsx +0 -146
- package/tests/i18n/language-detect.test.ts +0 -54
- package/tests/i18n/locale-parity.test.ts +0 -25
- package/tests/i18n/useTranslation.test.tsx +0 -45
- package/tests/keymap.test.ts +0 -18
- package/tests/navigator/SceneNavigator.test.tsx +0 -177
- package/tests/navigator/StatisticsDialog.test.tsx +0 -63
- package/tests/navigator/scene-list.test.ts +0 -71
- package/tests/print-paginator.test.ts +0 -82
- package/tests/shell/VersionHistory.test.tsx +0 -129
- package/tests/spellcheck/hunspell.test.ts +0 -82
- package/tests/spellcheck/spellcheck-plugin.test.ts +0 -56
- package/tests/styles.test.ts +0 -315
- package/tests/templates/templates.test.ts +0 -83
- package/tests/titlepage/TitlePageDialog.test.tsx +0 -90
- package/tests/titlepage/apply-title-page.test.ts +0 -61
- package/tests/titlepage/frontmatter-form.test.ts +0 -115
- package/tests/toolbar-actions.test.ts +0 -93
- package/tests/voice-commands.test.ts +0 -58
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -11
- package/vitest.setup.ts +0 -65
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# @sutrata/editor
|
|
2
|
+
|
|
3
|
+
The React screenplay editor behind [Sutrata](https://github.com/sutrata/sutrata), for writing scripts in **Sutra**, a plain-text screenplay format for world languages. It's built on ProseMirror and handles Indic and other complex scripts properly:
|
|
4
|
+
- Text is stored in logical order.
|
|
5
|
+
- The cursor and selection move by grapheme cluster (user-perceived character).
|
|
6
|
+
- Find/replace matches after NFC normalization, so differently encoded forms of the same text still match.
|
|
7
|
+
|
|
8
|
+
This package contains the complete editor:
|
|
9
|
+
- WYSIWYG and source modes, with smart Enter that cycles through screenplay elements.
|
|
10
|
+
- A scene navigator, find/replace, a title-page form and screenplay styles.
|
|
11
|
+
- Statistics, autocomplete and spellcheck.
|
|
12
|
+
- Export to PDF, DOCX, Fountain and workflow reports, including romanized exports.
|
|
13
|
+
- Localized UI.
|
|
14
|
+
|
|
15
|
+
Sutra parsing and serialization come from [`@sutrata/parser`](https://www.npmjs.com/package/@sutrata/parser).
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @sutrata/editor react react-dom
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`react` and `react-dom` (^18.3) are peer dependencies.
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
The editor doesn't read or write files itself. You pass it a `StorageAdapter`, and it saves, opens and keeps version history through that adapter. The same editor can therefore run on local files, in a desktop shell or against a server.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import React from 'react'
|
|
31
|
+
import { createRoot } from 'react-dom/client'
|
|
32
|
+
import {
|
|
33
|
+
TranslationProvider,
|
|
34
|
+
LanguageProvider,
|
|
35
|
+
DocumentProvider,
|
|
36
|
+
AppShell,
|
|
37
|
+
type StorageAdapter,
|
|
38
|
+
} from '@sutrata/editor'
|
|
39
|
+
import '@sutrata/editor/dist/shell/fonts/fonts.css'
|
|
40
|
+
import '@sutrata/editor/dist/styles/screenplay.css'
|
|
41
|
+
|
|
42
|
+
const storageAdapter: StorageAdapter = {
|
|
43
|
+
// documents and version history
|
|
44
|
+
saveDocument: async (path, content) => { /* ... */ },
|
|
45
|
+
loadDocument: async (path) => null,
|
|
46
|
+
listVersions: async (path) => [],
|
|
47
|
+
// file dialogs
|
|
48
|
+
openFile: async () => null, // { name, content, handle }
|
|
49
|
+
openDocx: async () => null, // { name, buffer }
|
|
50
|
+
openStyleJson: async () => null, // { name, text }
|
|
51
|
+
saveFile: async (name, content, handle) => null, // { savedName, handle }
|
|
52
|
+
// custom screenplay styles
|
|
53
|
+
saveStyle: async (style) => {},
|
|
54
|
+
loadAllStyles: async () => [],
|
|
55
|
+
deleteStyle: async (id) => {},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
createRoot(document.getElementById('root')!).render(
|
|
59
|
+
<TranslationProvider>
|
|
60
|
+
<LanguageProvider>
|
|
61
|
+
<DocumentProvider storageAdapter={storageAdapter}>
|
|
62
|
+
<AppShell />
|
|
63
|
+
</DocumentProvider>
|
|
64
|
+
</LanguageProvider>
|
|
65
|
+
</TranslationProvider>,
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`StorageAdapter` also has optional methods: `saveVersion`, `deleteAllVersions`, `persistFileHandle` and `restoreFileHandle`. For a complete implementation built on IndexedDB and the File System Access API, see [`local-storage-adapter.ts`](https://github.com/sutrata/sutrata/blob/main/packages/app/src/local-storage-adapter.ts) in the Sutrata app.
|
|
70
|
+
|
|
71
|
+
Inside the providers, `useDocument()` gives you the current Sutra text, its parsed AST and the editor state.
|
|
72
|
+
|
|
73
|
+
### Fonts
|
|
74
|
+
|
|
75
|
+
`fonts.css` declares Noto font faces for every supported script, loaded from `/fonts/*.woff2` on your own site. This package does not include the font files. Copy them from [`packages/app/public/fonts`](https://github.com/sutrata/sutrata/tree/main/packages/app/public/fonts) into your app's `/fonts/` path, or use your own `@font-face` rules. Without them, some scripts may display as missing-glyph boxes (tofu).
|
|
76
|
+
|
|
77
|
+
## Extension points
|
|
78
|
+
|
|
79
|
+
Beyond `StorageAdapter`, the package exports type definitions for more extension points: `AIProvider`, `SpeechProvider`, `SessionContext`, `PanelRegistry`, `CommandRegistry`, `ExportRegistry`, `CollabBinding` and `DecorationProvider`. **These are type-only previews and are not wired into the editor yet.** Their shapes may change before 1.0.
|
|
80
|
+
|
|
81
|
+
## Status
|
|
82
|
+
|
|
83
|
+
Pre-1.0. The API may change between minor versions.
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
[GPL-3.0-or-later](https://github.com/sutrata/sutrata/blob/main/packages/editor/LICENSE).
|
package/package.json
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sutrata/editor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "React + ProseMirror screenplay editor for Sutra, with first-class support for Indic and other complex scripts.",
|
|
4
5
|
"license": "GPL-3.0-or-later",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"sutra",
|
|
8
|
+
"screenplay",
|
|
9
|
+
"editor",
|
|
10
|
+
"prosemirror",
|
|
11
|
+
"react",
|
|
12
|
+
"indic",
|
|
13
|
+
"unicode",
|
|
14
|
+
"fountain"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/sutrata/sutrata/tree/main/packages/editor#readme",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/sutrata/sutrata.git",
|
|
20
|
+
"directory": "packages/editor"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/sutrata/sutrata/issues"
|
|
24
|
+
},
|
|
5
25
|
"type": "module",
|
|
6
26
|
"main": "./dist/index.js",
|
|
7
27
|
"types": "./dist/index.d.ts",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"test": "vitest run",
|
|
12
|
-
"test:watch": "vitest"
|
|
13
|
-
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
14
31
|
"dependencies": {
|
|
15
32
|
"@codemirror/commands": "^6.10.3",
|
|
16
33
|
"@codemirror/language": "^6.12.3",
|
|
@@ -18,7 +35,6 @@
|
|
|
18
35
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
19
36
|
"@codemirror/view": "^6.43.1",
|
|
20
37
|
"@lezer/highlight": "^1.2.3",
|
|
21
|
-
"@sutrata/parser": "workspace:*",
|
|
22
38
|
"diff": "^9.0.0",
|
|
23
39
|
"docx": "^9.7.1",
|
|
24
40
|
"jszip": "^3.10.1",
|
|
@@ -30,6 +46,9 @@
|
|
|
30
46
|
"prosemirror-state": "^1.4.3",
|
|
31
47
|
"prosemirror-transform": "^1.9.0",
|
|
32
48
|
"prosemirror-view": "^1.33.0",
|
|
49
|
+
"@sutrata/parser": "0.1.1"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
33
52
|
"react": "^18.3.0",
|
|
34
53
|
"react-dom": "^18.3.0"
|
|
35
54
|
},
|
|
@@ -41,7 +60,15 @@
|
|
|
41
60
|
"@types/react-dom": "^18.3.0",
|
|
42
61
|
"@vitejs/plugin-react": "^4.3.0",
|
|
43
62
|
"jsdom": "^29.1.1",
|
|
63
|
+
"react": "^18.3.0",
|
|
64
|
+
"react-dom": "^18.3.0",
|
|
44
65
|
"typescript": "^5.4.0",
|
|
45
66
|
"vitest": "^1.6.0"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "node scripts/generate-providers.mjs && tsc && node scripts/copy-assets.mjs",
|
|
70
|
+
"generate:providers": "node scripts/generate-providers.mjs",
|
|
71
|
+
"test": "vitest run",
|
|
72
|
+
"test:watch": "vitest"
|
|
46
73
|
}
|
|
47
|
-
}
|
|
74
|
+
}
|
package/scripts/copy-assets.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, copyFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
6
|
-
|
|
7
|
-
const files = [
|
|
8
|
-
['src/shell/fonts/fonts.css', 'dist/shell/fonts/fonts.css'],
|
|
9
|
-
['src/styles/screenplay.css', 'dist/styles/screenplay.css'],
|
|
10
|
-
['src/desktop-api.d.ts', 'dist/desktop-api.d.ts'],
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
for (const [from, to] of files) {
|
|
14
|
-
mkdirSync(dirname(join(root, to)), { recursive: true });
|
|
15
|
-
copyFileSync(join(root, from), join(root, to));
|
|
16
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
// Generates src/ai/generated-providers.json (and a copy at
|
|
2
|
-
// packages/app/public/models-config.json) from the community-maintained
|
|
3
|
-
// all-llm-provider-list registry, at build time.
|
|
4
|
-
//
|
|
5
|
-
// Only providers Sutrata can actually drive are kept: ones with a real
|
|
6
|
-
// env_variable (i.e. a "paste an API key" auth model — this drops
|
|
7
|
-
// OAuth/browser-cookie/local-only/no-auth entries) and either
|
|
8
|
-
// openai_compatible: true, or Anthropic (the one vendor ai-client.ts still
|
|
9
|
-
// calls via a bespoke request shape, since Anthropic has no OpenAI-compat
|
|
10
|
-
// endpoint). Google/Gemini is retargeted at its official OpenAI-compat base
|
|
11
|
-
// URL (https://generativelanguage.googleapis.com/v1beta/openai) so it flows
|
|
12
|
-
// through the generic branch too, rather than needing its own adapter.
|
|
13
|
-
//
|
|
14
|
-
// TODO(future): this list is currently refreshed only when this script is
|
|
15
|
-
// re-run at build time. A follow-up could instead fetch the upstream list
|
|
16
|
-
// live each time the user opens the AI settings/onboarding dialog, so the
|
|
17
|
-
// provider catalog stays current without a rebuild — intentionally not done
|
|
18
|
-
// here to keep this change scoped.
|
|
19
|
-
|
|
20
|
-
import { writeFileSync, existsSync } from 'node:fs';
|
|
21
|
-
import { dirname, join } from 'node:path';
|
|
22
|
-
import { fileURLToPath } from 'node:url';
|
|
23
|
-
|
|
24
|
-
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
25
|
-
const editorOutPath = join(root, 'src/ai/generated-providers.json');
|
|
26
|
-
const appOutPath = join(root, '../app/public/models-config.json');
|
|
27
|
-
|
|
28
|
-
const SOURCE_URL = 'https://raw.githubusercontent.com/foisalislambd/all-llm-provider-list/main/data/providers.json';
|
|
29
|
-
|
|
30
|
-
// id/baseUrl overrides for vendors Sutrata treats specially. Ids double as
|
|
31
|
-
// localStorage key suffixes (sutrata_api_key_<id>) and, for anthropic, as
|
|
32
|
-
// invokeProvider's branch discriminator — they must stay stable across
|
|
33
|
-
// regenerations regardless of what the upstream slug says.
|
|
34
|
-
//
|
|
35
|
-
// `models` overrides are needed because the upstream list's popular_models
|
|
36
|
-
// sometimes holds human-readable display names (e.g. "Claude Opus 4.8")
|
|
37
|
-
// rather than API-ready model ids — fine for a dropdown label, but wrong if
|
|
38
|
-
// sent verbatim as the `model` field. These two are the ids actually used
|
|
39
|
-
// for testConnection() before listModels() has a chance to fetch live ones;
|
|
40
|
-
// everyone else relies on listModels() to correct a bad static id at
|
|
41
|
-
// first use.
|
|
42
|
-
const OVERRIDES = {
|
|
43
|
-
anthropic: {
|
|
44
|
-
id: 'anthropic',
|
|
45
|
-
baseUrl: 'https://api.anthropic.com/v1',
|
|
46
|
-
models: [
|
|
47
|
-
{ id: 'claude-opus-5', name: 'Claude Opus 5' },
|
|
48
|
-
{ id: 'claude-sonnet-5', name: 'Claude Sonnet 5' },
|
|
49
|
-
{ id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5' },
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
'google-ai-studio': {
|
|
53
|
-
id: 'gemini',
|
|
54
|
-
baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai',
|
|
55
|
-
models: [
|
|
56
|
-
{ id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash' },
|
|
57
|
-
{ id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro' },
|
|
58
|
-
{ id: 'gemini-2.0-flash-lite', name: 'Gemini 2.0 Flash Lite' },
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
OVERRIDES.gemini = OVERRIDES['google-ai-studio'];
|
|
63
|
-
OVERRIDES.google = OVERRIDES['google-ai-studio'];
|
|
64
|
-
|
|
65
|
-
const ESSENTIAL_IDS = new Set(['anthropic', 'gemini', 'groq']);
|
|
66
|
-
|
|
67
|
-
function isSupported(entry) {
|
|
68
|
-
if (!entry.env_variable || !entry.api_base_url) return false;
|
|
69
|
-
const override = OVERRIDES[entry.slug];
|
|
70
|
-
return entry.openai_compatible === true || override?.id === 'anthropic';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function toProviderConfig(entry) {
|
|
74
|
-
const override = OVERRIDES[entry.slug];
|
|
75
|
-
const id = override?.id ?? entry.slug;
|
|
76
|
-
const baseUrl = override?.baseUrl ?? entry.api_base_url;
|
|
77
|
-
const config = {
|
|
78
|
-
id,
|
|
79
|
-
name: entry.name,
|
|
80
|
-
baseUrl,
|
|
81
|
-
models: override?.models ?? (entry.popular_models ?? []).map((m) => ({ id: m, name: m })),
|
|
82
|
-
};
|
|
83
|
-
if (ESSENTIAL_IDS.has(id)) config.essential = true;
|
|
84
|
-
return config;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function main() {
|
|
88
|
-
let source;
|
|
89
|
-
try {
|
|
90
|
-
const res = await fetch(SOURCE_URL);
|
|
91
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
92
|
-
source = await res.json();
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.warn(`[generate-providers] Failed to fetch ${SOURCE_URL}: ${e}. Leaving existing generated files untouched.`);
|
|
95
|
-
if (!existsSync(editorOutPath)) {
|
|
96
|
-
console.error('[generate-providers] No existing generated-providers.json to fall back to — build will use the compiled-in defaults only.');
|
|
97
|
-
}
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const entries = Array.isArray(source) ? source : source.providers ?? [];
|
|
102
|
-
const seen = new Set();
|
|
103
|
-
const providers = [];
|
|
104
|
-
for (const entry of entries) {
|
|
105
|
-
if (!isSupported(entry)) continue;
|
|
106
|
-
const config = toProviderConfig(entry);
|
|
107
|
-
if (seen.has(config.id)) continue; // first match wins (upstream list order)
|
|
108
|
-
seen.add(config.id);
|
|
109
|
-
providers.push(config);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const output = {
|
|
113
|
-
generatedAt: new Date().toISOString(),
|
|
114
|
-
source: 'https://github.com/foisalislambd/all-llm-provider-list',
|
|
115
|
-
providers,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const json = JSON.stringify(output, null, 2) + '\n';
|
|
119
|
-
writeFileSync(editorOutPath, json);
|
|
120
|
-
|
|
121
|
-
const appConfig = { providers: output.providers };
|
|
122
|
-
writeFileSync(appOutPath, JSON.stringify(appConfig, null, 2) + '\n');
|
|
123
|
-
|
|
124
|
-
console.log(`[generate-providers] Wrote ${providers.length} providers to ${editorOutPath} and ${appOutPath}.`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
await main();
|