@stackable-labs/mcp-app-extension 0.8.0 → 0.9.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.
package/dist/index.js CHANGED
@@ -43,12 +43,13 @@ export const appStore = createStore<AppState>({
43
43
  {
44
44
  path: "surfaces/Content.tsx",
45
45
  title: "Content Surface with Loading State",
46
- code: `import { ui, useStore, useContextData, Surface } from '@stackable-labs/sdk-extension-react'
46
+ code: `import { ui, useStore, useContextData, useSettings, Surface } from '@stackable-labs/sdk-extension-react'
47
47
  import { appStore } from '../store'
48
48
 
49
49
  export function Content() {
50
50
  const viewState = useStore(appStore, (s) => s.viewState)
51
51
  const { loading } = useContextData()
52
+ const settings = useSettings() // Non-secret settings from settingsSchema
52
53
 
53
54
  if (loading) {
54
55
  return (
@@ -143,19 +144,33 @@ export function createApi(query: QueryFn) {
143
144
  }
144
145
 
145
146
  // \u2500\u2500 data.fetch wrapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
147
+ //
148
+ // For API keys and secrets, use {{settings.xxx}} placeholders in headers.
149
+ // The proxy resolves them server-side \u2014 the real secret never enters extension code.
150
+ // Declare secret fields in manifest.json settingsSchema with "secret": true.
146
151
 
147
152
  const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string
148
153
 
149
154
  export function createFetchApi(fetch: FetchFn) {
150
155
  return {
151
156
  async getItems(): Promise<unknown[]> {
152
- const result = await fetch(\`\${API_BASE_URL}/items\`, { method: 'GET' })
157
+ const result = await fetch(\`\${API_BASE_URL}/items\`, {
158
+ method: 'GET',
159
+ headers: {
160
+ 'X-API-Key': '{{settings.apiKey}}',
161
+ },
162
+ })
153
163
  if (!result.ok) throw new Error(\`getItems failed: \${result.status}\`)
154
164
  return result.data as unknown[]
155
165
  },
156
166
 
157
167
  async getItem(itemId: string): Promise<unknown> {
158
- const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, { method: 'GET' })
168
+ const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, {
169
+ method: 'GET',
170
+ headers: {
171
+ 'X-API-Key': '{{settings.apiKey}}',
172
+ },
173
+ })
159
174
  if (!result.ok) throw new Error(\`getItem failed: \${result.status}\`)
160
175
  return result.data as unknown
161
176
  },
@@ -182,12 +197,13 @@ export const appStore = createStore<AppState>({
182
197
  {
183
198
  path: "surfaces/Content.tsx",
184
199
  title: "Current Content Surface",
185
- code: `import { ui, useStore, useContextData, Surface } from '@stackable-labs/sdk-extension-react'
200
+ code: `import { ui, useStore, useContextData, useSettings, Surface } from '@stackable-labs/sdk-extension-react'
186
201
  import { appStore } from '../store'
187
202
 
188
203
  export function Content() {
189
204
  const viewState = useStore(appStore, (s) => s.viewState)
190
205
  const { loading } = useContextData()
206
+ const settings = useSettings() // Non-secret settings from settingsSchema
191
207
 
192
208
  if (loading) {
193
209
  return (
@@ -251,19 +267,33 @@ export function createApi(query: QueryFn) {
251
267
  }
252
268
 
253
269
  // \u2500\u2500 data.fetch wrapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
270
+ //
271
+ // For API keys and secrets, use {{settings.xxx}} placeholders in headers.
272
+ // The proxy resolves them server-side \u2014 the real secret never enters extension code.
273
+ // Declare secret fields in manifest.json settingsSchema with "secret": true.
254
274
 
255
275
  const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string
256
276
 
257
277
  export function createFetchApi(fetch: FetchFn) {
258
278
  return {
259
279
  async getItems(): Promise<unknown[]> {
260
- const result = await fetch(\`\${API_BASE_URL}/items\`, { method: 'GET' })
280
+ const result = await fetch(\`\${API_BASE_URL}/items\`, {
281
+ method: 'GET',
282
+ headers: {
283
+ 'X-API-Key': '{{settings.apiKey}}',
284
+ },
285
+ })
261
286
  if (!result.ok) throw new Error(\`getItems failed: \${result.status}\`)
262
287
  return result.data as unknown[]
263
288
  },
264
289
 
265
290
  async getItem(itemId: string): Promise<unknown> {
266
- const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, { method: 'GET' })
291
+ const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, {
292
+ method: 'GET',
293
+ headers: {
294
+ 'X-API-Key': '{{settings.apiKey}}',
295
+ },
296
+ })
267
297
  if (!result.ok) throw new Error(\`getItem failed: \${result.status}\`)
268
298
  return result.data as unknown
269
299
  },
@@ -3682,8 +3712,11 @@ var CAPABILITY_SNIPPETS2 = {
3682
3712
  const result = await capabilities.data.query({ path: '/your-endpoint', method: 'GET' })`,
3683
3713
  "data.fetch": `const capabilities = useCapabilities()
3684
3714
  const response = await capabilities.data.fetch('https://api.example.com/endpoint')`,
3685
- "context.read": `const capabilities = useCapabilities()
3686
- const ctx = await capabilities.context.read()`,
3715
+ "context.read": `// Read host context + extension settings
3716
+ const { customerId, settings } = useContextData()
3717
+
3718
+ // Or use the convenience hook for settings only
3719
+ const settings = useSettings()`,
3687
3720
  "actions.toast": `const capabilities = useCapabilities()
3688
3721
  capabilities.actions.toast({ type: 'success', message: 'Done!' })`,
3689
3722
  "actions.invoke": `const capabilities = useCapabilities()
package/dist/server.js CHANGED
@@ -41,12 +41,13 @@ export const appStore = createStore<AppState>({
41
41
  {
42
42
  path: "surfaces/Content.tsx",
43
43
  title: "Content Surface with Loading State",
44
- code: `import { ui, useStore, useContextData, Surface } from '@stackable-labs/sdk-extension-react'
44
+ code: `import { ui, useStore, useContextData, useSettings, Surface } from '@stackable-labs/sdk-extension-react'
45
45
  import { appStore } from '../store'
46
46
 
47
47
  export function Content() {
48
48
  const viewState = useStore(appStore, (s) => s.viewState)
49
49
  const { loading } = useContextData()
50
+ const settings = useSettings() // Non-secret settings from settingsSchema
50
51
 
51
52
  if (loading) {
52
53
  return (
@@ -141,19 +142,33 @@ export function createApi(query: QueryFn) {
141
142
  }
142
143
 
143
144
  // \u2500\u2500 data.fetch wrapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
145
+ //
146
+ // For API keys and secrets, use {{settings.xxx}} placeholders in headers.
147
+ // The proxy resolves them server-side \u2014 the real secret never enters extension code.
148
+ // Declare secret fields in manifest.json settingsSchema with "secret": true.
144
149
 
145
150
  const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string
146
151
 
147
152
  export function createFetchApi(fetch: FetchFn) {
148
153
  return {
149
154
  async getItems(): Promise<unknown[]> {
150
- const result = await fetch(\`\${API_BASE_URL}/items\`, { method: 'GET' })
155
+ const result = await fetch(\`\${API_BASE_URL}/items\`, {
156
+ method: 'GET',
157
+ headers: {
158
+ 'X-API-Key': '{{settings.apiKey}}',
159
+ },
160
+ })
151
161
  if (!result.ok) throw new Error(\`getItems failed: \${result.status}\`)
152
162
  return result.data as unknown[]
153
163
  },
154
164
 
155
165
  async getItem(itemId: string): Promise<unknown> {
156
- const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, { method: 'GET' })
166
+ const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, {
167
+ method: 'GET',
168
+ headers: {
169
+ 'X-API-Key': '{{settings.apiKey}}',
170
+ },
171
+ })
157
172
  if (!result.ok) throw new Error(\`getItem failed: \${result.status}\`)
158
173
  return result.data as unknown
159
174
  },
@@ -180,12 +195,13 @@ export const appStore = createStore<AppState>({
180
195
  {
181
196
  path: "surfaces/Content.tsx",
182
197
  title: "Current Content Surface",
183
- code: `import { ui, useStore, useContextData, Surface } from '@stackable-labs/sdk-extension-react'
198
+ code: `import { ui, useStore, useContextData, useSettings, Surface } from '@stackable-labs/sdk-extension-react'
184
199
  import { appStore } from '../store'
185
200
 
186
201
  export function Content() {
187
202
  const viewState = useStore(appStore, (s) => s.viewState)
188
203
  const { loading } = useContextData()
204
+ const settings = useSettings() // Non-secret settings from settingsSchema
189
205
 
190
206
  if (loading) {
191
207
  return (
@@ -249,19 +265,33 @@ export function createApi(query: QueryFn) {
249
265
  }
250
266
 
251
267
  // \u2500\u2500 data.fetch wrapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
268
+ //
269
+ // For API keys and secrets, use {{settings.xxx}} placeholders in headers.
270
+ // The proxy resolves them server-side \u2014 the real secret never enters extension code.
271
+ // Declare secret fields in manifest.json settingsSchema with "secret": true.
252
272
 
253
273
  const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string
254
274
 
255
275
  export function createFetchApi(fetch: FetchFn) {
256
276
  return {
257
277
  async getItems(): Promise<unknown[]> {
258
- const result = await fetch(\`\${API_BASE_URL}/items\`, { method: 'GET' })
278
+ const result = await fetch(\`\${API_BASE_URL}/items\`, {
279
+ method: 'GET',
280
+ headers: {
281
+ 'X-API-Key': '{{settings.apiKey}}',
282
+ },
283
+ })
259
284
  if (!result.ok) throw new Error(\`getItems failed: \${result.status}\`)
260
285
  return result.data as unknown[]
261
286
  },
262
287
 
263
288
  async getItem(itemId: string): Promise<unknown> {
264
- const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, { method: 'GET' })
289
+ const result = await fetch(\`\${API_BASE_URL}/items/\${itemId}\`, {
290
+ method: 'GET',
291
+ headers: {
292
+ 'X-API-Key': '{{settings.apiKey}}',
293
+ },
294
+ })
265
295
  if (!result.ok) throw new Error(\`getItem failed: \${result.status}\`)
266
296
  return result.data as unknown
267
297
  },
@@ -3680,8 +3710,11 @@ var CAPABILITY_SNIPPETS2 = {
3680
3710
  const result = await capabilities.data.query({ path: '/your-endpoint', method: 'GET' })`,
3681
3711
  "data.fetch": `const capabilities = useCapabilities()
3682
3712
  const response = await capabilities.data.fetch('https://api.example.com/endpoint')`,
3683
- "context.read": `const capabilities = useCapabilities()
3684
- const ctx = await capabilities.context.read()`,
3713
+ "context.read": `// Read host context + extension settings
3714
+ const { customerId, settings } = useContextData()
3715
+
3716
+ // Or use the convenience hook for settings only
3717
+ const settings = useSettings()`,
3685
3718
  "actions.toast": `const capabilities = useCapabilities()
3686
3719
  capabilities.actions.toast({ type: 'success', message: 'Done!' })`,
3687
3720
  "actions.invoke": `const capabilities = useCapabilities()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackable-labs/mcp-app-extension",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mcp-app-extension": "./dist/index.js"