@nordcraft/runtime 1.0.14 → 1.0.16

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.
@@ -5,9 +5,9 @@ import type {
5
5
  SupportedNamespaces,
6
6
  } from '@nordcraft/core/dist/component/component.types'
7
7
  import { applyFormula } from '@nordcraft/core/dist/formula/formula'
8
- import type { RequireFields } from '@nordcraft/core/dist/types'
9
8
  import { mapObject } from '@nordcraft/core/dist/utils/collections'
10
9
  import { isDefined } from '@nordcraft/core/dist/utils/util'
10
+ import { isContextApiV2 } from '../api/apiUtils'
11
11
  import { createLegacyAPI } from '../api/createAPI'
12
12
  import { createAPI } from '../api/createAPIv2'
13
13
  import { isContextProvider } from '../context/isContextProvider'
@@ -146,35 +146,36 @@ export function createComponent({
146
146
  },
147
147
  })
148
148
  } else {
149
- apis[name] = createAPI(api, {
150
- ...ctx,
151
- apis,
152
- component,
153
- dataSignal: componentDataSignal,
154
- abortSignal: abortController.signal,
155
- isRootComponent: false,
156
- formulaCache,
157
- package: node.package ?? ctx.package,
158
- triggerEvent: (eventTrigger, data) => {
159
- const eventHandler = Object.values(node.events).find(
160
- (e) => e.trigger === eventTrigger,
161
- )
162
- if (eventHandler) {
163
- eventHandler.actions.forEach((action) =>
164
- handleAction(action, { ...dataSignal.get(), Event: data }, ctx),
149
+ apis[name] = createAPI({
150
+ apiRequest: api,
151
+ ctx: {
152
+ ...ctx,
153
+ apis,
154
+ component,
155
+ dataSignal: componentDataSignal,
156
+ abortSignal: abortController.signal,
157
+ isRootComponent: false,
158
+ formulaCache,
159
+ package: node.package ?? ctx.package,
160
+ triggerEvent: (eventTrigger, data) => {
161
+ const eventHandler = Object.values(node.events).find(
162
+ (e) => e.trigger === eventTrigger,
165
163
  )
166
- }
164
+ if (eventHandler) {
165
+ eventHandler.actions.forEach((action) =>
166
+ handleAction(action, { ...dataSignal.get(), Event: data }, ctx),
167
+ )
168
+ }
169
+ },
167
170
  },
171
+ componentData: componentDataSignal.get(),
168
172
  })
169
173
  }
170
174
  })
171
175
  Object.values(apis)
172
- .filter(
173
- (api): api is RequireFields<ContextApi, 'triggerActions'> =>
174
- api.triggerActions !== undefined,
175
- )
176
+ .filter(isContextApiV2)
176
177
  .forEach((api) => {
177
- api.triggerActions()
178
+ api.triggerActions(componentDataSignal.get())
178
179
  })
179
180
 
180
181
  const onEvent = (eventTrigger: string, data: any) => {
@@ -11,6 +11,7 @@ import type { Signal } from '../signal/signal'
11
11
  import type {
12
12
  ComponentChild,
13
13
  ComponentContext,
14
+ ContextApi,
14
15
  FormulaCache,
15
16
  LocationSignal,
16
17
  PreviewShowSignal,
@@ -22,7 +23,7 @@ interface RenderComponentProps {
22
23
  component: Component
23
24
  components: Component[]
24
25
  dataSignal: Signal<ComponentData>
25
- apis: Record<string, { fetch: Function; destroy: Function }>
26
+ apis: Record<string, ContextApi>
26
27
  abortSignal: AbortSignal
27
28
  onEvent: (event: string, data: unknown) => void
28
29
  isRootComponent: boolean
@@ -8,15 +8,16 @@ import { applyFormula } from '@nordcraft/core/dist/formula/formula'
8
8
  import { createStylesheet } from '@nordcraft/core/dist/styling/style.css'
9
9
  import type { Theme } from '@nordcraft/core/dist/styling/theme'
10
10
  import { theme as defaultTheme } from '@nordcraft/core/dist/styling/theme.const'
11
- import type { RequireFields, Toddle } from '@nordcraft/core/dist/types'
11
+ import type { Toddle } from '@nordcraft/core/dist/types'
12
12
  import { mapObject } from '@nordcraft/core/dist/utils/collections'
13
+ import { isContextApiV2 } from '../api/apiUtils'
13
14
  import { createLegacyAPI } from '../api/createAPI'
14
15
  import { createAPI } from '../api/createAPIv2'
15
16
  import { renderComponent } from '../components/renderComponent'
16
17
  import { isContextProvider } from '../context/isContextProvider'
17
18
  import type { Signal } from '../signal/signal'
18
19
  import { signal } from '../signal/signal'
19
- import type { ComponentContext, ContextApi, LocationSignal } from '../types'
20
+ import type { ComponentContext, LocationSignal } from '../types'
20
21
 
21
22
  /**
22
23
  * Base class for all toddle components
@@ -97,17 +98,18 @@ export class ToddleComponent extends HTMLElement {
97
98
  if (isLegacyApi(api)) {
98
99
  this.#ctx.apis[name] = createLegacyAPI(api, this.#ctx)
99
100
  } else {
100
- this.#ctx.apis[name] = createAPI(api, this.#ctx)
101
+ this.#ctx.apis[name] = createAPI({
102
+ apiRequest: api,
103
+ ctx: this.#ctx,
104
+ componentData: this.#signal.get(),
105
+ })
101
106
  }
102
107
  },
103
108
  )
104
109
  Object.values(this.#ctx.apis)
105
- .filter(
106
- (api): api is RequireFields<ContextApi, 'triggerActions'> =>
107
- api.triggerActions !== undefined,
108
- )
110
+ .filter(isContextApiV2)
109
111
  .forEach((api) => {
110
- api.triggerActions()
112
+ api.triggerActions(this.#signal.get())
111
113
  })
112
114
 
113
115
  let providers = this.#ctx.providers
@@ -48,6 +48,7 @@ import { signal } from './signal/signal'
48
48
  import { insertStyles, styleToCss } from './styles/style'
49
49
  import type {
50
50
  ComponentContext,
51
+ ContextApiV2,
51
52
  LocationSignal,
52
53
  PreviewShowSignal,
53
54
  } from './types'
@@ -724,7 +725,7 @@ export const createRoot = (
724
725
  },
725
726
  },
726
727
  }))
727
- ctx?.apis[apiKey]?.fetch({})
728
+ void ctx?.apis[apiKey]?.fetch({} as any)
728
729
  break
729
730
  case 'drag-started':
730
731
  const draggedElement = getDOMNodeFromNodeId(selectedNodeId)
@@ -1319,11 +1320,16 @@ export const createRoot = (
1319
1320
  newCtx.apis[api] = createLegacyAPI(apiInstance, newCtx)
1320
1321
  }
1321
1322
  } else {
1322
- if (!newCtx.apis[api]) {
1323
- newCtx.apis[api] = createAPI(apiInstance, newCtx)
1323
+ const existingApi = newCtx.apis[api] as ContextApiV2 | undefined
1324
+ if (!existingApi) {
1325
+ newCtx.apis[api] = createAPI({
1326
+ apiRequest: apiInstance,
1327
+ ctx: newCtx,
1328
+ componentData: dataSignal.get(),
1329
+ })
1324
1330
  } else {
1325
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1326
- newCtx.apis[api].update && newCtx.apis[api].update(apiInstance)
1331
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1332
+ existingApi?.update(apiInstance, dataSignal.get())
1327
1333
  }
1328
1334
  }
1329
1335
  }
@@ -9,6 +9,7 @@ import { applyFormula } from '@nordcraft/core/dist/formula/formula'
9
9
  import { mapValues, omitKeys } from '@nordcraft/core/dist/utils/collections'
10
10
  import { isDefined, toBoolean } from '@nordcraft/core/dist/utils/util'
11
11
  import fastDeepEqual from 'fast-deep-equal'
12
+ import { isContextApiV2 } from '../api/apiUtils'
12
13
  import type { ComponentContext, Location } from '../types'
13
14
  import { getLocationUrl } from '../utils/url'
14
15
 
@@ -233,61 +234,56 @@ export function handleAction(
233
234
  }
234
235
  case 'Fetch': {
235
236
  const api = ctx.apis[action.api]
237
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
236
238
  if (!api) {
237
239
  console.error('The api ', action.api, 'does not exist')
238
240
  return
239
241
  }
240
242
 
241
- const isv2 = ctx.component.apis?.[action.api]?.version === 2
242
-
243
- // Evaluate potential inputs here to make sure the api have the right values
244
- // This is needed if the inputs are formulas referencing workflow parameters
245
- const actionInputs = isv2
246
- ? mapValues(action.inputs ?? {}, (input) =>
247
- applyFormula(input.formula, {
248
- data,
249
- component: ctx.component,
250
- formulaCache: ctx.formulaCache,
251
- root: ctx.root,
252
- package: ctx.package,
253
- toddle: ctx.toddle,
254
- env: ctx.env,
255
- }),
256
- )
257
- : undefined
258
-
259
- const actionModels = isv2
260
- ? {
261
- onCompleted: action.onSuccess?.actions,
262
- onFailed: action.onError?.actions,
263
- onMessage: action.onMessage?.actions,
264
- }
265
- : undefined
266
-
267
- const triggerActions = (actions: ActionModel[]) => {
268
- // Actions from the fetch action is handled by the api itself
269
- if (isv2) {
270
- return
243
+ if (isContextApiV2(api)) {
244
+ // Evaluate potential inputs here to make sure the api have the right values
245
+ // This is needed if the inputs are formulas referencing workflow parameters
246
+ const actionInputs = mapValues(action.inputs ?? {}, (input) =>
247
+ applyFormula(input.formula, {
248
+ data,
249
+ component: ctx.component,
250
+ formulaCache: ctx.formulaCache,
251
+ root: ctx.root,
252
+ package: ctx.package,
253
+ toddle: ctx.toddle,
254
+ env: ctx.env,
255
+ }),
256
+ )
257
+ const actionModels = {
258
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
259
+ onCompleted: action.onSuccess?.actions ?? [],
260
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
261
+ onFailed: action.onError?.actions ?? [],
262
+ onMessage: action.onMessage?.actions ?? [],
271
263
  }
272
- for (const subAction of actions) {
273
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
274
- handleAction(
275
- subAction,
276
- { ...data, ...ctx.dataSignal.get() },
277
- ctx,
278
- event,
279
- )
264
+ void api.fetch({ actionInputs, actionModels, componentData: data })
265
+ } else {
266
+ const triggerActions = (actions: ActionModel[]) => {
267
+ for (const subAction of actions) {
268
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
269
+ handleAction(
270
+ subAction,
271
+ { ...data, ...ctx.dataSignal.get() },
272
+ ctx,
273
+ event,
274
+ )
275
+ }
280
276
  }
277
+ api.fetch().then(
278
+ () => {
279
+ triggerActions(action.onSuccess.actions)
280
+ },
281
+ () => {
282
+ triggerActions(action.onError.actions)
283
+ },
284
+ )
281
285
  }
282
286
 
283
- api.fetch({ actionInputs, actionModels }).then(
284
- () => {
285
- triggerActions(action.onSuccess.actions)
286
- },
287
- () => {
288
- triggerActions(action.onError.actions)
289
- },
290
- )
291
287
  break
292
288
  }
293
289
  case 'TriggerWorkflow': {
package/src/page.main.ts CHANGED
@@ -12,7 +12,6 @@ import type {
12
12
  FormulaHandler,
13
13
  FormulaHandlerV2,
14
14
  PluginActionV2,
15
- RequireFields,
16
15
  Toddle,
17
16
  } from '@nordcraft/core/dist/types'
18
17
  import { mapObject } from '@nordcraft/core/dist/utils/collections'
@@ -21,13 +20,14 @@ import * as libActions from '@nordcraft/std-lib/dist/actions'
21
20
  import * as libFormulas from '@nordcraft/std-lib/dist/formulas'
22
21
  import fastDeepEqual from 'fast-deep-equal'
23
22
  import { match } from 'path-to-regexp'
23
+ import { isContextApiV2 } from './api/apiUtils'
24
24
  import { createLegacyAPI } from './api/createAPI'
25
25
  import { createAPI } from './api/createAPIv2'
26
26
  import { renderComponent } from './components/renderComponent'
27
27
  import { isContextProvider } from './context/isContextProvider'
28
28
  import { initLogState, registerComponentToLogState } from './debug/logState'
29
29
  import { signal } from './signal/signal'
30
- import type { ComponentContext, ContextApi, LocationSignal } from './types'
30
+ import type { ComponentContext, LocationSignal } from './types'
31
31
 
32
32
  initLogState()
33
33
 
@@ -377,17 +377,18 @@ export const createRoot = (domNode: HTMLElement) => {
377
377
  if (isLegacyApi(api)) {
378
378
  ctx.apis[name] = createLegacyAPI(api, ctx)
379
379
  } else {
380
- ctx.apis[name] = createAPI(api, ctx)
380
+ ctx.apis[name] = createAPI({
381
+ apiRequest: api,
382
+ ctx,
383
+ componentData: dataSignal.get(),
384
+ })
381
385
  }
382
386
  })
383
387
  // Trigger actions for all APIs after all of them are created.
384
388
  Object.values(ctx.apis)
385
- .filter(
386
- (api): api is RequireFields<ContextApi, 'triggerActions'> =>
387
- api.triggerActions !== undefined,
388
- )
389
+ .filter(isContextApiV2)
389
390
  .forEach((api) => {
390
- api.triggerActions()
391
+ api.triggerActions(dataSignal.get())
391
392
  })
392
393
 
393
394
  let providers = ctx.providers
package/src/types.d.ts CHANGED
@@ -1,13 +1,20 @@
1
+ import type { ApiRequest as CoreApiRequest } from '@nordcraft/core/dist/api/apiTypes'
1
2
  import type {
3
+ ActionModel,
2
4
  Component,
3
5
  ComponentData,
4
6
  } from '@nordcraft/core/dist/component/component.types'
5
- import type { ToddleEnv } from '@nordcraft/core/dist/formula/formula'
7
+ import type {
8
+ Formula,
9
+ ToddleEnv,
10
+ ValueOperationValue,
11
+ } from '@nordcraft/core/dist/formula/formula'
6
12
  import type {
7
13
  Toddle as NewToddle,
8
14
  Toddle,
9
15
  ToddleInternals,
10
16
  } from '@nordcraft/core/dist/types'
17
+ import type { ApiRequest } from './api/createAPI'
11
18
  import type { Signal } from './signal/signal'
12
19
 
13
20
  declare global {
@@ -77,11 +84,33 @@ export interface ComponentContext {
77
84
  env: ToddleEnv
78
85
  }
79
86
 
80
- export type ContextApi = {
81
- fetch: Function
87
+ export type ContextApi = ContextApiV1 | ContextApiV2
88
+
89
+ export interface ContextApiV1 {
90
+ fetch: (api?: ApiRequest) => Promise<unknown>
91
+ destroy: Function
92
+ }
93
+
94
+ export interface ContextApiV2 {
95
+ fetch: (args: {
96
+ actionInputs?: Record<
97
+ string,
98
+ | ValueOperationValue
99
+ | {
100
+ name: string
101
+ formula?: Formula
102
+ }
103
+ >
104
+ actionModels?: {
105
+ onCompleted: ActionModel[]
106
+ onFailed: ActionModel[]
107
+ onMessage: ActionModel[]
108
+ }
109
+ componentData: ComponentData
110
+ }) => Promise<unknown>
82
111
  destroy: Function
83
- update?: Function // for updating the dataSignal (v2 only)
84
- triggerActions?: Function // for triggering actions explicitly. Useful when initializing apis (v2 only)
112
+ update: (newApi: CoreApiRequest, componentData: ComponentData) => void // for updating the dataSignal
113
+ triggerActions: (componentData: ComponentData) => void // for triggering actions explicitly. Useful when initializing apis
85
114
  }
86
115
 
87
116
  export type FormulaCache = Record<