@narrative.io/jsonforms-provider-protocols 1.0.3

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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -0
  3. package/dist/_virtual/_plugin-vue_export-helper.js +11 -0
  4. package/dist/_virtual/_plugin-vue_export-helper.js.map +1 -0
  5. package/dist/core/cache.d.ts +8 -0
  6. package/dist/core/cache.d.ts.map +1 -0
  7. package/dist/core/cache.js +27 -0
  8. package/dist/core/cache.js.map +1 -0
  9. package/dist/core/jsonpath.d.ts +2 -0
  10. package/dist/core/jsonpath.d.ts.map +1 -0
  11. package/dist/core/jsonpath.js +40 -0
  12. package/dist/core/jsonpath.js.map +1 -0
  13. package/dist/core/registry.d.ts +8 -0
  14. package/dist/core/registry.d.ts.map +1 -0
  15. package/dist/core/registry.js +17 -0
  16. package/dist/core/registry.js.map +1 -0
  17. package/dist/core/templating.d.ts +3 -0
  18. package/dist/core/templating.d.ts.map +1 -0
  19. package/dist/core/templating.js +32 -0
  20. package/dist/core/templating.js.map +1 -0
  21. package/dist/core/types.d.ts +44 -0
  22. package/dist/core/types.d.ts.map +1 -0
  23. package/dist/index.d.ts +18 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +30 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/jsonforms-provider-protocols.css +4 -0
  28. package/dist/protocols/rest_api.d.ts +22 -0
  29. package/dist/protocols/rest_api.d.ts.map +1 -0
  30. package/dist/protocols/rest_api.js +92 -0
  31. package/dist/protocols/rest_api.js.map +1 -0
  32. package/dist/vue/components/ProviderAutocomplete.vue.d.ts +9 -0
  33. package/dist/vue/components/ProviderAutocomplete.vue.d.ts.map +1 -0
  34. package/dist/vue/components/ProviderAutocomplete.vue.js +68 -0
  35. package/dist/vue/components/ProviderAutocomplete.vue.js.map +1 -0
  36. package/dist/vue/components/ProviderAutocomplete.vue2.js +5 -0
  37. package/dist/vue/components/ProviderAutocomplete.vue2.js.map +1 -0
  38. package/dist/vue/components/ProviderSelect.vue.d.ts +9 -0
  39. package/dist/vue/components/ProviderSelect.vue.d.ts.map +1 -0
  40. package/dist/vue/components/ProviderSelect.vue.js +8 -0
  41. package/dist/vue/components/ProviderSelect.vue.js.map +1 -0
  42. package/dist/vue/components/ProviderSelect.vue2.js +74 -0
  43. package/dist/vue/components/ProviderSelect.vue2.js.map +1 -0
  44. package/dist/vue/composables/useProvider.d.ts +14 -0
  45. package/dist/vue/composables/useProvider.d.ts.map +1 -0
  46. package/dist/vue/composables/useProvider.js +76 -0
  47. package/dist/vue/composables/useProvider.js.map +1 -0
  48. package/dist/vue/index.d.ts +19 -0
  49. package/dist/vue/index.d.ts.map +1 -0
  50. package/dist/vue/index.js +36 -0
  51. package/dist/vue/index.js.map +1 -0
  52. package/dist/vue/testers.d.ts +2 -0
  53. package/dist/vue/testers.d.ts.map +1 -0
  54. package/dist/vue/testers.js +12 -0
  55. package/dist/vue/testers.js.map +1 -0
  56. package/package.json +100 -0
  57. package/src/core/cache.ts +23 -0
  58. package/src/core/jsonpath.ts +41 -0
  59. package/src/core/registry.ts +15 -0
  60. package/src/core/templating.ts +27 -0
  61. package/src/core/types.ts +46 -0
  62. package/src/index.ts +36 -0
  63. package/src/protocols/rest_api.ts +136 -0
  64. package/src/vue/components/ProviderAutocomplete.vue +54 -0
  65. package/src/vue/components/ProviderSelect.vue +70 -0
  66. package/src/vue/composables/useProvider.ts +111 -0
  67. package/src/vue/index.ts +44 -0
  68. package/src/vue/testers.ts +19 -0
  69. package/src/vue-shim.d.ts +9 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Narrative I/O
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # JSONForms Provider Protocols
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@narrative.io/jsonforms-provider-protocols.svg)](https://www.npmjs.com/package/@narrative.io/jsonforms-provider-protocols)
4
+ [![CI](https://github.com/narrative-io/jsonforms-provider-protocols/workflows/CI/badge.svg)](https://github.com/narrative-io/jsonforms-provider-protocols/actions/workflows/ci.yml)
5
+ [![Release](https://github.com/narrative-io/jsonforms-provider-protocols/workflows/Release%20Please/badge.svg)](https://github.com/narrative-io/jsonforms-provider-protocols/actions/workflows/release-please.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
8
+ [![Vue 3](https://img.shields.io/badge/Vue-3-4FC08D.svg)](https://vuejs.org/)
9
+ [![JSONForms](https://img.shields.io/badge/JSONForms-3.6+-ff6900.svg)](https://jsonforms.io/)
10
+
11
+ A Vue 3 library that adds dynamic data provider capabilities to [JSONForms](https://jsonforms.io/), enabling form fields to fetch and display data from various sources like REST APIs, databases, and custom protocols.
12
+
13
+ ## ✨ Features
14
+
15
+ - 🔌 **Protocol-based Architecture**: Extensible system for different data sources
16
+ - 🚀 **Vue 3 Integration**: Seamless integration with JSONForms Vue renderers
17
+ - 💾 **Built-in Caching**: TTL-based caching with configurable expiration
18
+ - 🔄 **Dynamic Data Loading**: Support for mount, focus, and query-based loading
19
+ - 🎯 **Template Support**: Dynamic URL and parameter templating
20
+ - 📦 **TypeScript Support**: Full TypeScript definitions included
21
+ - 🔐 **Authentication**: Flexible authentication mechanism support
22
+
23
+ ## 📦 Installation
24
+
25
+ ```bash
26
+ # Using bun (recommended)
27
+ bun add @narrative.io/jsonforms-provider-protocols
28
+
29
+ # Using npm
30
+ npm install @narrative.io/jsonforms-provider-protocols
31
+
32
+ # Peer dependencies
33
+ bun add @jsonforms/vue @jsonforms/core vue
34
+ ```
35
+
36
+ ## 🚀 Quick Start
37
+
38
+ ### 1. Register the Plugin
39
+
40
+ ```typescript
41
+ import { createApp } from 'vue'
42
+ import ProviderProtocols, { RestApiProtocol } from '@narrative.io/jsonforms-provider-protocols'
43
+
44
+ const app = createApp(App)
45
+
46
+ app.use(ProviderProtocols, {
47
+ protocols: [RestApiProtocol()]
48
+ })
49
+ ```
50
+
51
+ ### 2. Configure Your Form
52
+
53
+ ```json
54
+ {
55
+ "type": "Control",
56
+ "scope": "#/properties/country",
57
+ "options": {
58
+ "provider": {
59
+ "ref": "countries",
60
+ "protocol": "rest_api",
61
+ "config": {
62
+ "url": "https://api.example.com/countries",
63
+ "items": "$.data[*]",
64
+ "map": {
65
+ "label": "$.name",
66
+ "value": "$.code"
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### 3. Use in Vue
75
+
76
+ ```vue
77
+ <script setup lang="ts">
78
+ import { JsonForms } from '@jsonforms/vue'
79
+ import { providerRenderers } from '@narrative.io/jsonforms-provider-protocols/vue'
80
+ import { markRaw, ref } from 'vue'
81
+
82
+ const data = ref({ country: null })
83
+ const handleChange = (event) => data.value = event.data
84
+ </script>
85
+
86
+ <template>
87
+ <JsonForms
88
+ :data="data"
89
+ :schema="schema"
90
+ :uischema="uischema"
91
+ :renderers="markRaw(providerRenderers)"
92
+ @change="handleChange"
93
+ />
94
+ </template>
95
+ ```
96
+
97
+ ## 📖 Documentation
98
+
99
+ ### Getting Started
100
+ - [Installation & Setup](./docs/getting-started.md)
101
+ - [Basic Examples](./docs/examples/simple-dropdown.md)
102
+
103
+ ### Core Concepts
104
+ - [Protocols](./docs/protocols.md) - How to fetch and transform data
105
+ - [Authentication](./docs/authentication.md) - Configure and use authentication
106
+ - [Vue Components](./docs/components.md) - Available components and composables
107
+ - [API Reference](./docs/api/README.md) - Complete API documentation
108
+
109
+ ### Examples
110
+ - [Simple Dropdown](./docs/examples/simple-dropdown.md)
111
+ - [Cascading Dropdowns](./docs/examples/cascading-dropdowns.md)
112
+ - [Autocomplete Search](./docs/examples/autocomplete-search.md)
113
+ - [Custom Protocols](./docs/examples/custom-protocol.md)
114
+ - [Custom Renderers](./docs/examples/custom-renderer.md)
115
+ - [More Examples](./docs/examples/README.md)
116
+
117
+ ### Help & Troubleshooting
118
+ - [Troubleshooting Guide](./docs/troubleshooting.md)
119
+ - [GitHub Issues](https://github.com/narrative-io/jsonforms-provider-protocols/issues)
120
+
121
+ ## 🔧 Key Concepts
122
+
123
+ ### Protocols
124
+ Define how data is fetched and transformed:
125
+
126
+ ```typescript
127
+ const CustomProtocol: Protocol = {
128
+ protocol: 'my-api',
129
+ async resolve(config, context) {
130
+ const response = await fetch(config.url)
131
+ const data = await response.json()
132
+
133
+ return {
134
+ items: data.map(item => ({
135
+ label: item.name,
136
+ value: item.id
137
+ })),
138
+ ttl: 300
139
+ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ ### Template Variables
145
+ Create dynamic URLs using form data:
146
+
147
+ ```json
148
+ {
149
+ "url": "https://api.example.com/countries/{{data.country}}/states",
150
+ "query": { "search": "{{ui.query}}" }
151
+ }
152
+ ```
153
+
154
+ ### Load Strategies
155
+ Control when data is fetched:
156
+
157
+ - `mount` - Load when component mounts (default)
158
+ - `onFocus` - Load when field receives focus
159
+ - `query` - Load when user types (autocomplete)
160
+
161
+ ### Composables
162
+ Use providers directly in your components:
163
+
164
+ ```vue
165
+ <script setup>
166
+ import { useProvider } from '@narrative.io/jsonforms-provider-protocols/vue'
167
+
168
+ const { items, loading, error, reload } = useProvider(binding, context)
169
+ </script>
170
+ ```
171
+
172
+ ## 🛠 Development
173
+
174
+ ```bash
175
+ # Install dependencies
176
+ bun install
177
+
178
+ # Run tests
179
+ bun test
180
+
181
+ # Build library
182
+ bun run build
183
+
184
+ # Type checking
185
+ bunx vue-tsc --noEmit
186
+ ```
187
+
188
+ ## 🤝 Contributing
189
+
190
+ Contributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) and check out the [issue tracker](https://github.com/narrative-io/jsonforms-provider-protocols/issues).
191
+
192
+ ## 📄 License
193
+
194
+ MIT - see [LICENSE](./LICENSE) file for details.
195
+
196
+ ## 🆘 Support
197
+
198
+ - [Documentation](./docs/)
199
+ - [GitHub Issues](https://github.com/narrative-io/jsonforms-provider-protocols/issues)
200
+ - [Troubleshooting Guide](./docs/troubleshooting.md)
@@ -0,0 +1,11 @@
1
+ const _export_sfc = (sfc, props) => {
2
+ const target = sfc.__vccOpts || sfc;
3
+ for (const [key, val] of props) {
4
+ target[key] = val;
5
+ }
6
+ return target;
7
+ };
8
+ export {
9
+ _export_sfc as default
10
+ };
11
+ //# sourceMappingURL=_plugin-vue_export-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_plugin-vue_export-helper.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
@@ -0,0 +1,8 @@
1
+ export declare class TTLCache<T> {
2
+ private m;
3
+ get(k: string): T | undefined;
4
+ set(k: string, v: T, ttlSec?: number): void;
5
+ del(k: string): void;
6
+ }
7
+ export declare const cache: TTLCache<unknown>;
8
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"AACA,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,CAAC,CAA+B;IACxC,GAAG,CAAC,CAAC,EAAE,MAAM;IASb,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,SAAI;IAM/B,GAAG,CAAC,CAAC,EAAE,MAAM;CAGd;AACD,eAAO,MAAM,KAAK,mBAA0B,CAAC"}
@@ -0,0 +1,27 @@
1
+ class TTLCache {
2
+ m = /* @__PURE__ */ new Map();
3
+ get(k) {
4
+ const e = this.m.get(k);
5
+ if (!e) return void 0;
6
+ if (e.expiresAt !== 0 && Date.now() > e.expiresAt) {
7
+ this.m.delete(k);
8
+ return void 0;
9
+ }
10
+ return e.value;
11
+ }
12
+ set(k, v, ttlSec = 0) {
13
+ this.m.set(k, {
14
+ value: v,
15
+ expiresAt: ttlSec ? Date.now() + ttlSec * 1e3 : 0
16
+ });
17
+ }
18
+ del(k) {
19
+ this.m.delete(k);
20
+ }
21
+ }
22
+ const cache = new TTLCache();
23
+ export {
24
+ TTLCache,
25
+ cache
26
+ };
27
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sources":["../../src/core/cache.ts"],"sourcesContent":["type Entry<T> = { value: T; expiresAt: number };\nexport class TTLCache<T> {\n private m = new Map<string, Entry<T>>();\n get(k: string) {\n const e = this.m.get(k);\n if (!e) return undefined;\n if (e.expiresAt !== 0 && Date.now() > e.expiresAt) {\n this.m.delete(k);\n return undefined;\n }\n return e.value;\n }\n set(k: string, v: T, ttlSec = 0) {\n this.m.set(k, {\n value: v,\n expiresAt: ttlSec ? Date.now() + ttlSec * 1000 : 0,\n });\n }\n del(k: string) {\n this.m.delete(k);\n }\n}\nexport const cache = new TTLCache<unknown>();\n"],"names":[],"mappings":"AACO,MAAM,SAAY;AAAA,EACf,wBAAQ,IAAA;AAAA,EAChB,IAAI,GAAW;AACb,UAAM,IAAI,KAAK,EAAE,IAAI,CAAC;AACtB,QAAI,CAAC,EAAG,QAAO;AACf,QAAI,EAAE,cAAc,KAAK,KAAK,IAAA,IAAQ,EAAE,WAAW;AACjD,WAAK,EAAE,OAAO,CAAC;AACf,aAAO;AAAA,IACT;AACA,WAAO,EAAE;AAAA,EACX;AAAA,EACA,IAAI,GAAW,GAAM,SAAS,GAAG;AAC/B,SAAK,EAAE,IAAI,GAAG;AAAA,MACZ,OAAO;AAAA,MACP,WAAW,SAAS,KAAK,IAAA,IAAQ,SAAS,MAAO;AAAA,IAAA,CAClD;AAAA,EACH;AAAA,EACA,IAAI,GAAW;AACb,SAAK,EAAE,OAAO,CAAC;AAAA,EACjB;AACF;AACO,MAAM,QAAQ,IAAI,SAAA;"}
@@ -0,0 +1,2 @@
1
+ export declare function jp(obj: unknown, path: string): unknown[];
2
+ //# sourceMappingURL=jsonpath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonpath.d.ts","sourceRoot":"","sources":["../../src/core/jsonpath.ts"],"names":[],"mappings":"AAAA,wBAAgB,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAwCxD"}
@@ -0,0 +1,40 @@
1
+ function jp(obj, path) {
2
+ if (path === "$") return [obj];
3
+ if (path === "") return [obj];
4
+ if (!path || typeof path !== "string") return [];
5
+ if (path.startsWith("$[*]")) {
6
+ if (!Array.isArray(obj)) return [];
7
+ const remainingPath = path.slice(4);
8
+ if (!remainingPath) return obj;
9
+ if (remainingPath.startsWith(".")) {
10
+ const subPath = remainingPath.slice(1);
11
+ const results = [];
12
+ for (const item of obj) {
13
+ results.push(...jp(item, subPath));
14
+ }
15
+ return results;
16
+ }
17
+ return [];
18
+ }
19
+ const parts = path.replace(/^\$\./, "").split(".");
20
+ let current = [obj];
21
+ for (const part of parts) {
22
+ const next = [];
23
+ const m = part.match(/^(\w+)(\[\*\])?$/);
24
+ if (!m) return [];
25
+ const key = m[1];
26
+ if (!key) return [];
27
+ const star = !!m[2];
28
+ for (const c of current) {
29
+ const v = c?.[key];
30
+ if (star && Array.isArray(v)) next.push(...v);
31
+ else if (!star && v !== void 0) next.push(v);
32
+ }
33
+ current = next;
34
+ }
35
+ return current;
36
+ }
37
+ export {
38
+ jp
39
+ };
40
+ //# sourceMappingURL=jsonpath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonpath.js","sources":["../../src/core/jsonpath.ts"],"sourcesContent":["export function jp(obj: unknown, path: string): unknown[] {\n // naive: support \"$.a.b[*].c\" & \"$.items[*]\"\n if (path === \"$\") return [obj];\n if (path === \"\") return [obj]; // Empty string should behave like \"$\"\n if (!path || typeof path !== \"string\") return [];\n\n // Handle array at root with $[*]\n if (path.startsWith(\"$[*]\")) {\n if (!Array.isArray(obj)) return [];\n const remainingPath = path.slice(4); // Remove \"$[*]\"\n if (!remainingPath) return obj;\n if (remainingPath.startsWith(\".\")) {\n // Continue with remaining path for each array element\n const subPath = remainingPath.slice(1);\n const results: unknown[] = [];\n for (const item of obj) {\n results.push(...jp(item, subPath));\n }\n return results;\n }\n return [];\n }\n\n const parts = path.replace(/^\\$\\./, \"\").split(\".\");\n let current: unknown[] = [obj];\n for (const part of parts) {\n const next: unknown[] = [];\n const m = part.match(/^(\\w+)(\\[\\*\\])?$/);\n if (!m) return [];\n const key = m[1];\n if (!key) return [];\n const star = !!m[2];\n for (const c of current) {\n const v = (c as Record<string, unknown>)?.[key];\n if (star && Array.isArray(v)) next.push(...v);\n else if (!star && v !== undefined) next.push(v);\n }\n current = next;\n }\n return current;\n}\n"],"names":[],"mappings":"AAAO,SAAS,GAAG,KAAc,MAAyB;AAExD,MAAI,SAAS,IAAK,QAAO,CAAC,GAAG;AAC7B,MAAI,SAAS,GAAI,QAAO,CAAC,GAAG;AAC5B,MAAI,CAAC,QAAQ,OAAO,SAAS,iBAAiB,CAAA;AAG9C,MAAI,KAAK,WAAW,MAAM,GAAG;AAC3B,QAAI,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAA;AAChC,UAAM,gBAAgB,KAAK,MAAM,CAAC;AAClC,QAAI,CAAC,cAAe,QAAO;AAC3B,QAAI,cAAc,WAAW,GAAG,GAAG;AAEjC,YAAM,UAAU,cAAc,MAAM,CAAC;AACrC,YAAM,UAAqB,CAAA;AAC3B,iBAAW,QAAQ,KAAK;AACtB,gBAAQ,KAAK,GAAG,GAAG,MAAM,OAAO,CAAC;AAAA,MACnC;AACA,aAAO;AAAA,IACT;AACA,WAAO,CAAA;AAAA,EACT;AAEA,QAAM,QAAQ,KAAK,QAAQ,SAAS,EAAE,EAAE,MAAM,GAAG;AACjD,MAAI,UAAqB,CAAC,GAAG;AAC7B,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAkB,CAAA;AACxB,UAAM,IAAI,KAAK,MAAM,kBAAkB;AACvC,QAAI,CAAC,EAAG,QAAO,CAAA;AACf,UAAM,MAAM,EAAE,CAAC;AACf,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,UAAM,OAAO,CAAC,CAAC,EAAE,CAAC;AAClB,eAAW,KAAK,SAAS;AACvB,YAAM,IAAK,IAAgC,GAAG;AAC9C,UAAI,QAAQ,MAAM,QAAQ,CAAC,EAAG,MAAK,KAAK,GAAG,CAAC;AAAA,eACnC,CAAC,QAAQ,MAAM,OAAW,MAAK,KAAK,CAAC;AAAA,IAChD;AACA,cAAU;AAAA,EACZ;AACA,SAAO;AACT;"}
@@ -0,0 +1,8 @@
1
+ import type { Protocol } from "./types";
2
+ export declare class ProtocolRegistry {
3
+ private drivers;
4
+ register(p: Protocol): void;
5
+ get(name: string): Protocol;
6
+ }
7
+ export declare const registry: ProtocolRegistry;
8
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAA+B;IAC9C,QAAQ,CAAC,CAAC,EAAE,QAAQ;IAGpB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;CAK5B;AAED,eAAO,MAAM,QAAQ,kBAAyB,CAAC"}
@@ -0,0 +1,17 @@
1
+ class ProtocolRegistry {
2
+ drivers = /* @__PURE__ */ new Map();
3
+ register(p) {
4
+ this.drivers.set(p.protocol, p);
5
+ }
6
+ get(name) {
7
+ const p = this.drivers.get(name);
8
+ if (!p) throw new Error(`Protocol '${name}' not registered`);
9
+ return p;
10
+ }
11
+ }
12
+ const registry = new ProtocolRegistry();
13
+ export {
14
+ ProtocolRegistry,
15
+ registry
16
+ };
17
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sources":["../../src/core/registry.ts"],"sourcesContent":["import type { Protocol } from \"./types\";\n\nexport class ProtocolRegistry {\n private drivers = new Map<string, Protocol>();\n register(p: Protocol) {\n this.drivers.set(p.protocol, p);\n }\n get(name: string): Protocol {\n const p = this.drivers.get(name);\n if (!p) throw new Error(`Protocol '${name}' not registered`);\n return p;\n }\n}\n\nexport const registry = new ProtocolRegistry();\n"],"names":[],"mappings":"AAEO,MAAM,iBAAiB;AAAA,EACpB,8BAAc,IAAA;AAAA,EACtB,SAAS,GAAa;AACpB,SAAK,QAAQ,IAAI,EAAE,UAAU,CAAC;AAAA,EAChC;AAAA,EACA,IAAI,MAAwB;AAC1B,UAAM,IAAI,KAAK,QAAQ,IAAI,IAAI;AAC/B,QAAI,CAAC,EAAG,OAAM,IAAI,MAAM,aAAa,IAAI,kBAAkB;AAC3D,WAAO;AAAA,EACT;AACF;AAEO,MAAM,WAAW,IAAI,iBAAA;"}
@@ -0,0 +1,3 @@
1
+ export declare function renderTpl(str: string, ctx: unknown): string;
2
+ export declare function renderObj<T = unknown>(obj: unknown, ctx: unknown): T;
3
+ //# sourceMappingURL=templating.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templating.d.ts","sourceRoot":"","sources":["../../src/core/templating.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAY3D;AACD,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,CAapE"}
@@ -0,0 +1,32 @@
1
+ function renderTpl(str, ctx) {
2
+ return str.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_, path) => {
3
+ const trimmedPath = path.trim();
4
+ return String(
5
+ trimmedPath.split(".").reduce((a, k) => {
6
+ if (a && typeof a === "object" && k in a) {
7
+ return a[k];
8
+ }
9
+ return void 0;
10
+ }, ctx) ?? ""
11
+ );
12
+ });
13
+ }
14
+ function renderObj(obj, ctx) {
15
+ if (!obj || typeof obj !== "object") return obj;
16
+ const out = Array.isArray(obj) ? [] : {};
17
+ for (const [k, v] of Object.entries(obj)) {
18
+ if (typeof v === "string") {
19
+ out[k] = renderTpl(v, ctx);
20
+ } else if (v && typeof v === "object") {
21
+ out[k] = renderObj(v, ctx);
22
+ } else {
23
+ out[k] = v;
24
+ }
25
+ }
26
+ return out;
27
+ }
28
+ export {
29
+ renderObj,
30
+ renderTpl
31
+ };
32
+ //# sourceMappingURL=templating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templating.js","sources":["../../src/core/templating.ts"],"sourcesContent":["export function renderTpl(str: string, ctx: unknown): string {\n return str.replace(/\\{\\{\\s*([^}]+)\\s*\\}\\}/g, (_, path) => {\n const trimmedPath = path.trim();\n return String(\n trimmedPath.split(\".\").reduce((a: unknown, k: string) => {\n if (a && typeof a === \"object\" && k in a) {\n return (a as Record<string, unknown>)[k];\n }\n return undefined;\n }, ctx) ?? \"\",\n );\n });\n}\nexport function renderObj<T = unknown>(obj: unknown, ctx: unknown): T {\n if (!obj || typeof obj !== \"object\") return obj as T;\n const out: Record<string, unknown> | unknown[] = Array.isArray(obj) ? [] : {};\n for (const [k, v] of Object.entries(obj)) {\n if (typeof v === \"string\") {\n (out as Record<string, unknown>)[k] = renderTpl(v, ctx);\n } else if (v && typeof v === \"object\") {\n (out as Record<string, unknown>)[k] = renderObj(v, ctx);\n } else {\n (out as Record<string, unknown>)[k] = v;\n }\n }\n return out as T;\n}\n"],"names":[],"mappings":"AAAO,SAAS,UAAU,KAAa,KAAsB;AAC3D,SAAO,IAAI,QAAQ,0BAA0B,CAAC,GAAG,SAAS;AACxD,UAAM,cAAc,KAAK,KAAA;AACzB,WAAO;AAAA,MACL,YAAY,MAAM,GAAG,EAAE,OAAO,CAAC,GAAY,MAAc;AACvD,YAAI,KAAK,OAAO,MAAM,YAAY,KAAK,GAAG;AACxC,iBAAQ,EAA8B,CAAC;AAAA,QACzC;AACA,eAAO;AAAA,MACT,GAAG,GAAG,KAAK;AAAA,IAAA;AAAA,EAEf,CAAC;AACH;AACO,SAAS,UAAuB,KAAc,KAAiB;AACpE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAA2C,MAAM,QAAQ,GAAG,IAAI,CAAA,IAAK,CAAA;AAC3E,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,GAAG;AACxC,QAAI,OAAO,MAAM,UAAU;AACxB,UAAgC,CAAC,IAAI,UAAU,GAAG,GAAG;AAAA,IACxD,WAAW,KAAK,OAAO,MAAM,UAAU;AACpC,UAAgC,CAAC,IAAI,UAAU,GAAG,GAAG;AAAA,IACxD,OAAO;AACJ,UAAgC,CAAC,IAAI;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;"}
@@ -0,0 +1,44 @@
1
+ export type ProviderItem = {
2
+ label: string;
3
+ value: unknown;
4
+ meta?: Record<string, unknown>;
5
+ };
6
+ export type ProviderOutput = {
7
+ items: ProviderItem[];
8
+ ttl?: number;
9
+ etag?: string;
10
+ };
11
+ export type ProviderContext = {
12
+ data: unknown;
13
+ path: string;
14
+ signal: AbortSignal;
15
+ ui?: {
16
+ query?: string;
17
+ };
18
+ auth?: Record<string, unknown>;
19
+ };
20
+ export interface Protocol<Cfg = unknown> {
21
+ protocol: string;
22
+ resolve(cfg: Cfg, ctx: ProviderContext): Promise<ProviderOutput>;
23
+ }
24
+ export interface ProviderBinding {
25
+ ref: string;
26
+ protocol: string;
27
+ config?: unknown;
28
+ auth?: AuthConfig;
29
+ cacheTTL?: number;
30
+ load?: "mount" | "onFocus" | "query";
31
+ }
32
+ export type Mapping = {
33
+ label: string;
34
+ value: string;
35
+ meta?: Record<string, string>;
36
+ };
37
+ export interface AuthConfig {
38
+ use?: string;
39
+ apiKey?: string | (() => string);
40
+ bearer?: string | (() => string);
41
+ token?: string | (() => string);
42
+ [key: string]: unknown;
43
+ }
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,QAAQ,CAAC,GAAG,GAAG,OAAO;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
@@ -0,0 +1,18 @@
1
+ import type { App } from "vue";
2
+ import type { Protocol, AuthConfig } from "./core/types";
3
+ export { cache } from "./core/cache";
4
+ export * from "./core/jsonpath";
5
+ export { registry } from "./core/registry";
6
+ export * from "./core/templating";
7
+ export * from "./core/types";
8
+ export { RestApiProtocol } from "./protocols/rest_api";
9
+ export * as vue from "./vue";
10
+ export interface ProviderConfig {
11
+ protocols?: Protocol[];
12
+ auth?: AuthConfig;
13
+ }
14
+ declare const _default: {
15
+ install(app: App, opts?: ProviderConfig): void;
16
+ };
17
+ export default _default;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG/B,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAElC,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;;iBAGc,GAAG,SAAS,cAAc;;AADzC,wBAYE"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import { cache } from "./core/cache.js";
2
+ import { registry } from "./core/registry.js";
3
+ import { jp } from "./core/jsonpath.js";
4
+ import { renderObj, renderTpl } from "./core/templating.js";
5
+ import { RestApiProtocol } from "./protocols/rest_api.js";
6
+ import * as vue_index from "./vue/index.js";
7
+ const index = {
8
+ install(app, opts) {
9
+ const reg = registry;
10
+ if (opts?.protocols) {
11
+ for (const p of opts.protocols) {
12
+ reg.register(p);
13
+ }
14
+ }
15
+ app.provide("providerRegistry", reg);
16
+ app.provide("providerCache", cache);
17
+ app.provide("providerAuth", opts?.auth ?? {});
18
+ }
19
+ };
20
+ export {
21
+ RestApiProtocol,
22
+ cache,
23
+ index as default,
24
+ jp,
25
+ registry,
26
+ renderObj,
27
+ renderTpl,
28
+ vue_index as vue
29
+ };
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { App } from \"vue\";\nimport { cache as globalCache } from \"./core/cache\";\nimport { registry as globalRegistry } from \"./core/registry\";\nimport type { Protocol, AuthConfig } from \"./core/types\";\n\nexport { cache } from \"./core/cache\";\nexport * from \"./core/jsonpath\";\nexport { registry } from \"./core/registry\";\nexport * from \"./core/templating\";\n// Core exports\nexport * from \"./core/types\";\n\n// Protocol exports\nexport { RestApiProtocol } from \"./protocols/rest_api\";\n\n// Vue exports\nexport * as vue from \"./vue\";\n\nexport interface ProviderConfig {\n protocols?: Protocol[];\n auth?: AuthConfig;\n}\n\nexport default {\n install(app: App, opts?: ProviderConfig) {\n const reg = globalRegistry;\n if (opts?.protocols) {\n for (const p of opts.protocols) {\n reg.register(p);\n }\n }\n app.provide(\"providerRegistry\", reg);\n app.provide(\"providerCache\", globalCache);\n app.provide(\"providerAuth\", opts?.auth ?? {});\n },\n};\n"],"names":["globalRegistry","globalCache"],"mappings":";;;;;;AAuBA,MAAA,QAAe;AAAA,EACb,QAAQ,KAAU,MAAuB;AACvC,UAAM,MAAMA;AACZ,QAAI,MAAM,WAAW;AACnB,iBAAW,KAAK,KAAK,WAAW;AAC9B,YAAI,SAAS,CAAC;AAAA,MAChB;AAAA,IACF;AACA,QAAI,QAAQ,oBAAoB,GAAG;AACnC,QAAI,QAAQ,iBAAiBC,KAAW;AACxC,QAAI,QAAQ,gBAAgB,MAAM,QAAQ,CAAA,CAAE;AAAA,EAC9C;AACF;"}
@@ -0,0 +1,4 @@
1
+
2
+ .provider-select select[data-v-1ad3fce8] {
3
+ min-width: 16rem;
4
+ }
@@ -0,0 +1,22 @@
1
+ import type { Protocol, AuthConfig } from "../core/types";
2
+ export type RestApiCfg = {
3
+ url: string;
4
+ method?: "GET" | "POST";
5
+ headers?: Record<string, string>;
6
+ query?: Record<string, unknown>;
7
+ body?: unknown;
8
+ items: string;
9
+ map: {
10
+ label: string;
11
+ value: string;
12
+ meta?: Record<string, string>;
13
+ };
14
+ paginate?: {
15
+ cursorPath: string;
16
+ param: string;
17
+ maxPages?: number;
18
+ };
19
+ auth?: AuthConfig;
20
+ };
21
+ export declare const RestApiProtocol: () => Protocol<RestApiCfg>;
22
+ //# sourceMappingURL=rest_api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest_api.d.ts","sourceRoot":"","sources":["../../src/protocols/rest_api.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,QAAQ,EAGR,UAAU,EACX,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACrE,QAAQ,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AA0DF,eAAO,MAAM,eAAe,QAAO,QAAQ,CAAC,UAAU,CA0DpD,CAAC"}
@@ -0,0 +1,92 @@
1
+ import { jp } from "../core/jsonpath.js";
2
+ import { renderTpl, renderObj } from "../core/templating.js";
3
+ function buildAuthHeaders(auth, globalAuth) {
4
+ const headers = {};
5
+ if (!auth) return headers;
6
+ if (auth.use && globalAuth?.[auth.use]) {
7
+ const globalValue = globalAuth[auth.use];
8
+ const value = typeof globalValue === "function" ? globalValue() : globalValue;
9
+ if (auth.use === "apiKey") {
10
+ headers["X-API-Key"] = String(value);
11
+ } else if (auth.use === "bearer") {
12
+ headers["Authorization"] = `Bearer ${value}`;
13
+ } else if (auth.use === "token") {
14
+ headers["Authorization"] = `Token ${value}`;
15
+ }
16
+ return headers;
17
+ }
18
+ if (auth.apiKey) {
19
+ const value = typeof auth.apiKey === "function" ? auth.apiKey() : auth.apiKey;
20
+ headers["X-API-Key"] = String(value);
21
+ }
22
+ if (auth.bearer) {
23
+ const value = typeof auth.bearer === "function" ? auth.bearer() : auth.bearer;
24
+ headers["Authorization"] = `Bearer ${value}`;
25
+ }
26
+ if (auth.token) {
27
+ const value = typeof auth.token === "function" ? auth.token() : auth.token;
28
+ headers["Authorization"] = `Token ${value}`;
29
+ }
30
+ for (const [key, value] of Object.entries(auth)) {
31
+ if (!["use", "apiKey", "bearer", "token"].includes(key) && value !== void 0) {
32
+ const authValue = typeof value === "function" ? value() : value;
33
+ headers[key] = String(authValue);
34
+ }
35
+ }
36
+ return headers;
37
+ }
38
+ const RestApiProtocol = () => ({
39
+ protocol: "rest_api",
40
+ async resolve(cfg, ctx) {
41
+ const ac = ctx.signal;
42
+ const out = [];
43
+ let cursor = null;
44
+ let page = 0;
45
+ do {
46
+ const url = new URL(renderTpl(cfg.url, { data: ctx.data, ui: ctx.ui }));
47
+ const q = renderObj(cfg.query ?? {}, {
48
+ data: ctx.data,
49
+ ui: ctx.ui
50
+ });
51
+ for (const [k, v] of Object.entries(q))
52
+ if (v !== void 0 && v !== "") url.searchParams.set(k, String(v));
53
+ if (cursor && cfg.paginate)
54
+ url.searchParams.set(cfg.paginate.param, String(cursor));
55
+ const baseHeaders = renderObj(cfg.headers ?? {}, {
56
+ data: ctx.data
57
+ });
58
+ const authHeaders = buildAuthHeaders(cfg.auth, ctx.auth);
59
+ const headers = { ...baseHeaders, ...authHeaders };
60
+ const method = cfg.method ?? "GET";
61
+ const requestInit = {
62
+ method,
63
+ headers,
64
+ signal: ac
65
+ };
66
+ if (method !== "GET" && cfg.body) {
67
+ requestInit.body = JSON.stringify(
68
+ renderObj(cfg.body, { data: ctx.data })
69
+ );
70
+ }
71
+ const res = await fetch(url.toString(), requestInit);
72
+ if (!res.ok) throw new Error(`REST ${res.status}`);
73
+ const json = await res.json();
74
+ const items = jp(json, cfg.items);
75
+ for (const it of items) {
76
+ const label = jp(it, cfg.map.label)[0];
77
+ const value = jp(it, cfg.map.value)[0];
78
+ const meta = cfg.map.meta ? Object.fromEntries(
79
+ Object.entries(cfg.map.meta).map(([k, p]) => [k, jp(it, p)[0]])
80
+ ) : void 0;
81
+ out.push({ label: String(label ?? ""), value, meta });
82
+ }
83
+ cursor = cfg.paginate ? jp(json, cfg.paginate.cursorPath)[0] : null;
84
+ page += 1;
85
+ } while (cfg.paginate && cursor && page < (cfg.paginate.maxPages ?? 5));
86
+ return { items: out, ttl: 300 };
87
+ }
88
+ });
89
+ export {
90
+ RestApiProtocol
91
+ };
92
+ //# sourceMappingURL=rest_api.js.map