@pikku/core 0.12.146 → 0.12.147

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.
@@ -62,6 +62,13 @@ async function resolveSession(wire, singletonServices, sessionService) {
62
62
  * @param packageName - The addon package it belongs to; `null` for the app.
63
63
  */
64
64
  export const addFunction = (funcName, funcConfig, packageName = null) => {
65
+ if (funcConfig.disabled) {
66
+ throw new Error(`Function '${funcName}' is disabled` +
67
+ (typeof funcConfig.disabled === 'string'
68
+ ? ` (${funcConfig.disabled})`
69
+ : '') +
70
+ ' and cannot be registered.');
71
+ }
65
72
  pikkuState(packageName, 'function', 'functions').set(funcName, funcConfig);
66
73
  };
67
74
  export const getFunctionNames = (packageName = null) => {
@@ -128,6 +128,14 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
128
128
  version?: number;
129
129
  /** Filters this function in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
130
130
  tags?: string[];
131
+ /**
132
+ * Switches the function off: `true`, or a string saying why. The build
133
+ * leaves it out of every map, client and wiring, and refuses (PKU562)
134
+ * anything that still references it, so marking a function believed dead
135
+ * proves it. The source keeps type-checking; deleting the flag turns it
136
+ * back on.
137
+ */
138
+ disabled?: true | string;
131
139
  /** Makes the function callable from outside as `POST /rpc/<name>`. Without a session requirement, a permission or an addon gate, that means callable by anyone. */
132
140
  expose?: boolean;
133
141
  /**
@@ -15,7 +15,7 @@ import type { CoreScheduledTask, ScheduledTasksMeta } from '../wirings/scheduler
15
15
  import type { CoreWorkflow, WorkflowsRuntimeMeta } from '../wirings/workflow/workflow.types.js';
16
16
  import type { CoreFeature } from '../wirings/workflow/scenario.types.js';
17
17
  import type { CoreTrigger, CoreTriggerSource, TriggerMeta, TriggerSourceMeta } from '../wirings/trigger/trigger.types.js';
18
- import type { CreateConfig, CreateSingletonServices, CreateWireServices, CoreConfig, CoreSingletonServices, CoreServices, CoreUserSession } from './core.types.js';
18
+ import type { CreateConfig, CreateSingletonServices, CreateWireServices, CoreSingletonServices } from './core.types.js';
19
19
  import type { FunctionsMeta } from '../function/function-meta.types.js';
20
20
  import type { CorePikkuMiddleware, CorePikkuMiddlewareGroup } from '../middleware/middleware.types.js';
21
21
  import type { CorePikkuChannelMiddleware } from '../wirings/channel/channel.types.js';
@@ -168,10 +168,11 @@ export interface PikkuPackageState {
168
168
  permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
169
169
  };
170
170
  package: {
171
+ /** Every package's own factories, each typed where it is defined. */
171
172
  factories: {
172
- createConfig?: CreateConfig<CoreConfig>;
173
- createSingletonServices?: CreateSingletonServices<CoreConfig, CoreSingletonServices>;
174
- createWireServices?: CreateWireServices<CoreSingletonServices, CoreServices, CoreUserSession>;
173
+ createConfig?: CreateConfig<any>;
174
+ createSingletonServices?: CreateSingletonServices<any, any>;
175
+ createWireServices?: CreateWireServices<any, any, any>;
175
176
  } | null;
176
177
  singletonServices: CoreSingletonServices | null;
177
178
  /** The pikkuBetterAuth factory, self-registered when auth.ts is evaluated.
@@ -1,3 +1,13 @@
1
+ import { PikkuError } from '../../errors/error-handler.js';
1
2
  import type { PikkuRawWire } from '../../types/core.types.js';
2
3
  export declare const addonMayReach: (caller: string, funcName: string) => boolean;
3
4
  export declare const addonCallerOf: (wire: PikkuRawWire) => string | undefined;
5
+ export declare class AddonNotUsedError extends PikkuError {
6
+ constructor(caller: string, target: string);
7
+ }
8
+ /**
9
+ * The name an addon's call resolves to on this host, through its `uses`.
10
+ *
11
+ * knowledge: decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md
12
+ */
13
+ export declare const mapAddonCall: (caller: string | undefined, funcName: string) => string;
@@ -1,4 +1,5 @@
1
1
  import { ForbiddenError } from '../../errors/errors.js';
2
+ import { PikkuError, addError } from '../../errors/error-handler.js';
2
3
  import { ADDON_HEADER } from '../../middleware/addon-scope-cap.js';
3
4
  import { pikkuState } from '../../pikku-state.js';
4
5
  export const addonMayReach = (caller, funcName) => {
@@ -19,3 +20,31 @@ export const addonCallerOf = (wire) => {
19
20
  }
20
21
  return name;
21
22
  };
23
+ export class AddonNotUsedError extends PikkuError {
24
+ constructor(caller, target) {
25
+ super(`Addon '${caller}' called '${target}' but does not list it in its wireAddon 'uses'.`);
26
+ }
27
+ }
28
+ addError(AddonNotUsedError, {
29
+ status: 403,
30
+ message: 'Addon called another addon it does not use.',
31
+ });
32
+ /**
33
+ * The name an addon's call resolves to on this host, through its `uses`.
34
+ *
35
+ * knowledge: decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md
36
+ */
37
+ export const mapAddonCall = (caller, funcName) => {
38
+ if (!caller)
39
+ return funcName;
40
+ const colon = funcName.indexOf(':');
41
+ if (colon === -1)
42
+ return funcName;
43
+ const prefix = funcName.slice(0, colon);
44
+ if (prefix === caller)
45
+ return funcName;
46
+ const mapped = pikkuState(null, 'addons', 'packages').get(caller)?.uses?.[prefix];
47
+ if (mapped)
48
+ return `${mapped}${funcName.slice(colon)}`;
49
+ throw new AddonNotUsedError(caller, funcName);
50
+ };
@@ -1,7 +1,7 @@
1
1
  export { wireAddon } from './wire-addon.js';
2
2
  export type { WireAddonConfig } from './wire-addon.js';
3
- export { defineScreens } from './define-screens.js';
4
- export type { ScreensManifest, AddonScreen, AddonComponentScreen, AddonAppScreen, } from './define-screens.js';
3
+ export { pikkuStudio } from './pikku-studio.js';
4
+ export type { StudioManifest, StudioScreen, StudioComponentScreen, StudioAppScreen, StudioNav, } from './pikku-studio.js';
5
5
  export { wireRemoteAddon } from './wire-remote-addon.js';
6
6
  export type { WireRemoteAddonConfig, RemoteAddonAuth, } from './wire-remote-addon.js';
7
7
  export { resolveRemoteAddonToken, RemoteAddonAuthError, } from './remote-addon-auth.js';
@@ -1,4 +1,4 @@
1
1
  export { wireAddon } from './wire-addon.js';
2
- export { defineScreens } from './define-screens.js';
2
+ export { pikkuStudio } from './pikku-studio.js';
3
3
  export { wireRemoteAddon } from './wire-remote-addon.js';
4
4
  export { resolveRemoteAddonToken, RemoteAddonAuthError, } from './remote-addon-auth.js';
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Where an addon screen shows in Studio's navigation. Leave it out and the
3
+ * screen is routed but not listed.
4
+ */
5
+ export type StudioNav = {
6
+ area: 'rail' | 'team' | 'project' | 'account';
7
+ /** The icon's name. */
8
+ icon: string;
9
+ order: number;
10
+ /** Names a function of the addon that returns a count shown on the entry. */
11
+ badge?: string;
12
+ };
13
+ type StudioScreenBase = {
14
+ /** The route path, under the prefix its `scope` gives it. */
15
+ path: string;
16
+ /** A message key in the addon's catalog, `messages/{locale}.json`. It is also the nav label. */
17
+ title: string;
18
+ nav?: StudioNav;
19
+ /** Takes over the core screen at the same path. Only first-party addons may use it. */
20
+ replaces?: boolean;
21
+ /** `'bare'` renders the screen without the shell. */
22
+ layout?: 'bare';
23
+ /** Hides the screen and its nav for viewers without access. The addon's functions must enforce the same scopes: hiding a screen is not access control. */
24
+ scopes?: string[];
25
+ } & ({
26
+ /** `'studio'` gives `/<path>`, `'team'` gives `/<team>/<path>`. */
27
+ scope: 'studio' | 'team';
28
+ needsApp?: never;
29
+ } | {
30
+ /** `/<team>/<project>[/<target>]/<path>`. */
31
+ scope: 'project';
32
+ /** The screen needs the project's app running. Defaults to `false`. */
33
+ needsApp?: boolean;
34
+ });
35
+ /** A screen rendered by the host from the addon's source. */
36
+ export type StudioComponentScreen = StudioScreenBase & {
37
+ component: () => Promise<{
38
+ default: unknown;
39
+ }>;
40
+ };
41
+ /** A static program the host serves in a sandboxed iframe. */
42
+ export type StudioAppScreen = StudioScreenBase & {
43
+ /** Directory of the built program, relative to the addon package. */
44
+ app: string;
45
+ };
46
+ /** One screen an addon ships: either a component the host renders or a static app it serves in a sandboxed iframe. */
47
+ export type StudioScreen = StudioComponentScreen | StudioAppScreen;
48
+ /** The manifest passed to `pikkuStudio`: the addon's title, a message key, and its screens. */
49
+ export type StudioManifest = {
50
+ title: string;
51
+ screens: StudioScreen[];
52
+ };
53
+ /**
54
+ * Declares the screens and nav an addon brings to Pikku Studio. Read
55
+ * statically by `pikku all`, so every field must be a literal. Titles are
56
+ * message keys in the addon's own catalog, `messages/{locale}.json`: a key
57
+ * missing from `messages/en.json` fails the build.
58
+ */
59
+ export declare const pikkuStudio: (manifest: StudioManifest) => StudioManifest;
60
+ export {};
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Declares the screens and nav an addon brings to Pikku Studio. Read
3
+ * statically by `pikku all`, so every field must be a literal. Titles are
4
+ * message keys in the addon's own catalog, `messages/{locale}.json`: a key
5
+ * missing from `messages/en.json` fails the build.
6
+ */
7
+ export const pikkuStudio = (manifest) => manifest;
@@ -46,18 +46,22 @@ export type WireAddonConfig = {
46
46
  /** Filters this addon in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
47
47
  tags?: string[];
48
48
  /**
49
- * Mounts the screens the addon ships (see `defineScreens`) in the host under
50
- * `/addons/<name>`. Without it the addon's screens are ignored. The package
51
- * must declare at least one, or `pikku all` rejects the wiring.
49
+ * Mounts the screens the addon ships (see `pikkuStudio`) in the host, each at
50
+ * the path its `scope` gives it. Without it the addon's screens are ignored.
51
+ * The package must declare at least one, or `pikku all` rejects the wiring.
52
52
  */
53
53
  ui?: boolean;
54
54
  /** Required of every function in the addon, on top of the function's own. */
55
55
  scopes?: string[];
56
56
  /**
57
- * The other addons this one may call, as `{ '<package>': '<name>' }`: the
58
- * package it was written against, and the name that package is wired under
59
- * in this app. The addon calls `'<package>:<function>'`; anything it did not
60
- * list is refused, whatever else the app has wired.
57
+ * The other addons this one may call, as `{ '<alias>': '<name>' }`: the name
58
+ * the addon calls another by, and the name that addon is wired under in this
59
+ * app — by `wireAddon` or `wireRemoteAddon`, either serves. The alias is the
60
+ * one the addon's package.json declares under `pikku.uses`
61
+ * (`{ "stripe": "@acme/addon-stripe@^1.0.0" }`), or, for an addon that lists
62
+ * plain names, the package name itself. The addon calls
63
+ * `'<alias>:<function>'`; anything it did not declare, or this app did not
64
+ * map, is refused, whatever else the app has wired.
61
65
  */
62
66
  uses?: Record<string, string>;
63
67
  /** Points a secret the addon reads at a different key in this deployment, so two instances can hold different credentials. */
@@ -1,4 +1,5 @@
1
1
  import { pikkuState } from '../../pikku-state.js';
2
+ import { mapAddonCall } from '../addon/addon-reach.js';
2
3
  import { runAgent, resumeAgentSync } from './agent-runner.js';
3
4
  import { streamAgent, resumeAgent, interruptAgent } from './agent-stream.js';
4
5
  import { wrapChannelWithAGUI } from './agent-agui.js';
@@ -31,10 +32,10 @@ export const createAgentRPC = (wire, options) => {
31
32
  }),
32
33
  });
33
34
  return {
34
- run: async (agentName, input) => asRunResult(await runAgent(agentName, input, params())),
35
+ run: async (agentName, input) => asRunResult(await runAgent(mapAddonCall(wire.addonNamespace, agentName), input, params())),
35
36
  stream: async (agentName, input, streamOptions) => {
36
37
  let currentRunId;
37
- await streamAgent(agentName, input, wrapChannelWithAGUI(streamingChannel(), {
38
+ await streamAgent(mapAddonCall(wire.addonNamespace, agentName), input, wrapChannelWithAGUI(streamingChannel(), {
38
39
  threadId: input.threadId,
39
40
  getRunId: () => currentRunId,
40
41
  }), params(), undefined, {
@@ -49,7 +50,9 @@ export const createAgentRPC = (wire, options) => {
49
50
  await resumeAgent({ runId, ...input }, wrapChannelWithAGUI(streamingChannel(), { runId }), params(), streamOptions);
50
51
  },
51
52
  interrupt: async (runId, reason) => interruptAgent({ runId, ...(reason ? { reason } : {}) }, { sessionService: options.sessionService }),
52
- approve: async (runId, approvals, expectedAgentName) => asRunResult(await resumeAgentSync(runId, approvals, { sessionService: options.sessionService }, expectedAgentName)),
53
+ approve: async (runId, approvals, expectedAgentName) => asRunResult(await resumeAgentSync(runId, approvals, { sessionService: options.sessionService }, expectedAgentName === undefined
54
+ ? undefined
55
+ : mapAddonCall(wire.addonNamespace, expectedAgentName))),
53
56
  };
54
57
  };
55
58
  /**
@@ -1,3 +1,4 @@
1
+ import { AddonNotUsedError } from '../addon/addon-reach.js';
1
2
  import type { CoreServices, PikkuRawWire } from '../../types/core.types.js';
2
3
  import type { SessionService } from '../../services/user-session-service.js';
3
4
  import type { CoreUserSession } from '../../types/core.types.js';
@@ -29,9 +30,7 @@ export declare class RemoteAddonFailedError extends PikkuError {
29
30
  export declare class RemoteAddonTimeoutError extends PikkuError {
30
31
  constructor(namespace: string, fnName: string, timeoutMs: number);
31
32
  }
32
- export declare class AddonNotUsedError extends PikkuError {
33
- constructor(caller: string, target: string);
34
- }
33
+ export { AddonNotUsedError };
35
34
  export declare const resolveNamespace: (namespacedFunction: string) => ResolvedFunction | null;
36
35
  export declare class ContextAwareRPCService {
37
36
  private services;
@@ -1,4 +1,4 @@
1
- import { addonCallerOf, addonMayReach } from '../addon/addon-reach.js';
1
+ import { AddonNotUsedError, addonCallerOf, addonMayReach, mapAddonCall, } from '../addon/addon-reach.js';
2
2
  import { forwardStepName, isCompensationStepName, } from '../../compensation-name.js';
3
3
  import { addonInstanceForNamespace } from '../addon/addon-runner.js';
4
4
  import { isAddonFunctionExposed } from '../addon/wire-addon.js';
@@ -166,15 +166,7 @@ const remoteAddonResponseError = async (res, namespace, fnName, logger) => {
166
166
  logger.error(`Remote addon '${namespace}:${fnName}' answered ${res.status}: ${body.slice(0, 1000)}`);
167
167
  return new RemoteAddonFailedError(namespace, fnName);
168
168
  };
169
- export class AddonNotUsedError extends PikkuError {
170
- constructor(caller, target) {
171
- super(`Addon '${caller}' called '${target}' but does not list it in its wireAddon 'uses'.`);
172
- }
173
- }
174
- addError(AddonNotUsedError, {
175
- status: 403,
176
- message: 'Addon called another addon it does not use.',
177
- });
169
+ export { AddonNotUsedError };
178
170
  export const resolveNamespace = (namespacedFunction) => {
179
171
  const colonIndex = namespacedFunction.indexOf(':');
180
172
  if (colonIndex === -1) {
@@ -367,18 +359,7 @@ export class ContextAwareRPCService {
367
359
  });
368
360
  }
369
361
  mapUsedAddon(funcName) {
370
- const caller = this.wire.addonNamespace;
371
- if (!caller)
372
- return funcName;
373
- const colon = funcName.indexOf(':');
374
- const prefix = funcName.slice(0, colon);
375
- if (prefix === caller)
376
- return funcName;
377
- const uses = pikkuState(null, 'addons', 'packages').get(caller)?.uses;
378
- const mapped = uses?.[prefix];
379
- if (mapped)
380
- return `${mapped}${funcName.slice(colon)}`;
381
- throw new AddonNotUsedError(caller, funcName);
362
+ return mapAddonCall(this.wire.addonNamespace, funcName);
382
363
  }
383
364
  /**
384
365
  * Resolution half of an addon RPC call: never executes anything, so an
@@ -737,7 +737,7 @@ async function invokeGraphNodeRpc(workflowService, rpcService, runId, stepId, no
737
737
  export async function executeGraphStep(workflowService, rpcService, runId, stepId, nodeId, rpcName, data, graphName) {
738
738
  try {
739
739
  let result;
740
- const subWorkflowMeta = pikkuState(null, 'workflows', 'meta')[rpcName];
740
+ const subWorkflowMeta = getWorkflowMeta(rpcName);
741
741
  const agentMeta = subWorkflowMeta
742
742
  ? undefined
743
743
  : pikkuState(null, 'agent', 'agentsMeta')[rpcName];
@@ -801,7 +801,7 @@ async function executeGraphNodeInline(workflowService, rpcService, runId, graphN
801
801
  await workflowService.setStepRunning(stepState.stepId);
802
802
  try {
803
803
  let result;
804
- const subWorkflowMeta = pikkuState(null, 'workflows', 'meta')[rpcName];
804
+ const subWorkflowMeta = getWorkflowMeta(rpcName);
805
805
  const agentMeta = subWorkflowMeta
806
806
  ? undefined
807
807
  : pikkuState(null, 'agent', 'agentsMeta')[rpcName];
@@ -691,8 +691,7 @@ export class PikkuWorkflowService {
691
691
  if (!run) {
692
692
  throw new Error(`Workflow run not found: ${runId}`);
693
693
  }
694
- const meta = pikkuState(null, 'workflows', 'meta');
695
- const workflowMeta = meta[run.workflow];
694
+ const workflowMeta = resolveWorkflowMeta(run.workflow)?.meta;
696
695
  const isGraphWorkflow = workflowMeta?.source === 'graph';
697
696
  let graphNodeId;
698
697
  if (isGraphWorkflow && workflowMeta?.nodes) {
@@ -709,7 +708,7 @@ export class PikkuWorkflowService {
709
708
  result = await executeGraphStep(this, rpcService, runId, stepState.stepId, graphNodeId, workflowMeta.nodes[graphNodeId].rpcName, data, run.workflow);
710
709
  }
711
710
  else {
712
- if (meta[rpcName]) {
711
+ if (resolveWorkflowMeta(rpcName)) {
713
712
  result = await startQueuedChildStep({
714
713
  startWorkflow: (...args) => this.startWorkflow(...args),
715
714
  setStepChildRunId: (...args) => this.setStepChildRunId(...args),
@@ -860,7 +859,7 @@ export class PikkuWorkflowService {
860
859
  if (resolvedStepOptions.virtualUser) {
861
860
  return resolvedStepOptions.virtualUser.invoke(rpcName, data);
862
861
  }
863
- if (pikkuState(null, 'workflows', 'meta')[rpcName]) {
862
+ if (resolveWorkflowMeta(rpcName)) {
864
863
  return runInlineChildStep({
865
864
  startWorkflow: (...args) => this.startWorkflow(...args),
866
865
  setStepChildRunId: (...args) => this.setStepChildRunId(...args),
@@ -2,6 +2,7 @@ import { DEFAULT_STEP_RETRIES, NO_COMPENSATE_STATE_PREFIX, WORKFLOW_TERMINAL_STA
2
2
  import { pikkuState } from '../../pikku-state.js';
3
3
  import { resolveNamespace } from '../rpc/rpc-runner.js';
4
4
  import { runningStepLease } from './workflow-step-lease.js';
5
+ import { isWorkflowName } from './workflow-meta-resolver.js';
5
6
  import { planUnwind } from './workflow-unwind-plan.js';
6
7
  const ENTERABLE = new Set([
7
8
  'running',
@@ -177,8 +178,7 @@ export const functionHasCompensation = (rpcName) => {
177
178
  ?.compensate === true
178
179
  : false;
179
180
  };
180
- export const isChildWorkflowRecord = (record) => !!record.rpcName &&
181
- pikkuState(null, 'workflows', 'meta')[record.rpcName] !== undefined;
181
+ export const isChildWorkflowRecord = (record) => !!record.rpcName && isWorkflowName(record.rpcName);
182
182
  export const recordHasCompensation = (record) => isChildWorkflowRecord(record)
183
183
  ? !!record.childRunId
184
184
  : !!record.rpcName && functionHasCompensation(record.rpcName);
@@ -9,3 +9,8 @@ export type ResolvedWorkflowMeta = {
9
9
  * `namespace:name` form — against the addon package that claims the namespace.
10
10
  */
11
11
  export declare const resolveWorkflowMeta: (name: string) => ResolvedWorkflowMeta | null;
12
+ /**
13
+ * Whether a step's rpcName names a workflow — the app's, or an addon's by
14
+ * `namespace:name` — and so starts a child run rather than an RPC.
15
+ */
16
+ export declare const isWorkflowName: (name: string) => boolean;
@@ -29,3 +29,8 @@ export const resolveWorkflowMeta = (name) => {
29
29
  resolvedName: localName,
30
30
  };
31
31
  };
32
+ /**
33
+ * Whether a step's rpcName names a workflow — the app's, or an addon's by
34
+ * `namespace:name` — and so starts a child run rather than an RPC.
35
+ */
36
+ export const isWorkflowName = (name) => resolveWorkflowMeta(name) !== null;
@@ -1,6 +1,7 @@
1
1
  import { getSingletonServices, pikkuState } from '../../pikku-state.js';
2
2
  import { getDurationInMilliseconds } from '../../time-utils.js';
3
3
  import { DEFAULT_STEP_RETRIES, forwardStepName } from './workflow-constants.js';
4
+ import { isWorkflowName } from './workflow-meta-resolver.js';
4
5
  const toKebab = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
5
6
  export const resolveWorkflowConfig = () => {
6
7
  const workflow = getSingletonServices().config?.workflow;
@@ -54,8 +55,7 @@ export const stepDispatchTarget = async (rpcName, stepName, parentIsInline) => {
54
55
  }
55
56
  return 'queue';
56
57
  }
57
- const isWorkflow = pikkuState(null, 'workflows', 'meta')[rpcName] !== undefined;
58
- if (!isWorkflow || !hasQueue) {
58
+ if (!isWorkflowName(rpcName) || !hasQueue) {
59
59
  return 'inline';
60
60
  }
61
61
  return (await parentIsInline()) ? 'inline' : 'queue';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.12.146",
3
+ "version": "0.12.147",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "sideEffects": [
26
26
  "./dist/errors/errors.js",
27
+ "./dist/wirings/addon/addon-reach.js",
27
28
  "./dist/wirings/addon/remote-addon-auth.js",
28
29
  "./dist/wirings/agent/agent-rpc.js",
29
30
  "./dist/wirings/rpc/rpc-runner.js",
@@ -1,34 +0,0 @@
1
- type AddonScreenBase = {
2
- /** Where the screen mounts under the addon, e.g. `/` or `/:id`. */
3
- path: string;
4
- title: string;
5
- /** Lists the screen in the host's navigation. */
6
- nav?: boolean;
7
- /** Required of the viewer to see the screen. The addon's functions must enforce the same scopes: hiding a screen is not access control. */
8
- scopes?: string[];
9
- };
10
- /** A screen rendered by the host from the addon's source. */
11
- export type AddonComponentScreen = AddonScreenBase & {
12
- component: () => Promise<{
13
- default: unknown;
14
- }>;
15
- };
16
- /** A static program the host serves in a sandboxed iframe. */
17
- export type AddonAppScreen = AddonScreenBase & {
18
- /** Directory of the built program, relative to the addon package. */
19
- app: string;
20
- };
21
- /** One screen an addon ships: either a component the host renders or a static app it serves in a sandboxed iframe. */
22
- export type AddonScreen = AddonComponentScreen | AddonAppScreen;
23
- /** The manifest passed to `defineScreens`: the addon's title, optional icon and its screens. */
24
- export type ScreensManifest = {
25
- title: string;
26
- icon?: string;
27
- screens: AddonScreen[];
28
- };
29
- /**
30
- * Declares the screens an addon ships, which the host mounts when it is wired
31
- * with `ui: true`. Read statically by `pikku all`, so `path`, `title`, `nav`, `scopes` and `app` must be literals.
32
- */
33
- export declare const defineScreens: (manifest: ScreensManifest) => ScreensManifest;
34
- export {};
@@ -1,5 +0,0 @@
1
- /**
2
- * Declares the screens an addon ships, which the host mounts when it is wired
3
- * with `ui: true`. Read statically by `pikku all`, so `path`, `title`, `nav`, `scopes` and `app` must be literals.
4
- */
5
- export const defineScreens = (manifest) => manifest;