@pikku/core 0.11.1 → 0.11.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.
Files changed (143) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/errors/error-handler.js +3 -3
  3. package/dist/function/function-runner.d.ts +4 -3
  4. package/dist/function/function-runner.js +60 -14
  5. package/dist/function/functions.types.d.ts +84 -5
  6. package/dist/function/functions.types.js +41 -1
  7. package/dist/index.d.ts +6 -2
  8. package/dist/index.js +5 -2
  9. package/dist/middleware/auth-apikey.d.ts +1 -1
  10. package/dist/middleware/auth-bearer.d.ts +1 -1
  11. package/dist/middleware/auth-cookie.d.ts +1 -1
  12. package/dist/middleware/timeout.d.ts +1 -1
  13. package/dist/middleware-runner.d.ts +3 -14
  14. package/dist/middleware-runner.js +8 -8
  15. package/dist/permissions.d.ts +3 -86
  16. package/dist/permissions.js +11 -67
  17. package/dist/pikku-state.d.ts +32 -104
  18. package/dist/pikku-state.js +140 -66
  19. package/dist/schema.d.ts +8 -6
  20. package/dist/schema.js +25 -13
  21. package/dist/services/workflow-service.d.ts +38 -0
  22. package/dist/services/workflow-service.js +1 -0
  23. package/dist/types/core.types.d.ts +12 -4
  24. package/dist/types/core.types.js +1 -1
  25. package/dist/types/state.types.d.ts +135 -0
  26. package/dist/types/state.types.js +1 -0
  27. package/dist/utils.d.ts +8 -0
  28. package/dist/utils.js +45 -0
  29. package/dist/wirings/channel/channel-handler.js +1 -1
  30. package/dist/wirings/channel/channel-runner.js +5 -5
  31. package/dist/wirings/channel/log-channels.js +1 -1
  32. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -2
  33. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  34. package/dist/wirings/cli/cli-runner.js +10 -10
  35. package/dist/wirings/cli/cli.types.d.ts +1 -0
  36. package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
  37. package/dist/wirings/forge-node/forge-node.types.js +38 -0
  38. package/dist/wirings/forge-node/index.d.ts +1 -0
  39. package/dist/wirings/forge-node/index.js +1 -0
  40. package/dist/wirings/http/http-runner.d.ts +2 -2
  41. package/dist/wirings/http/http-runner.js +21 -12
  42. package/dist/wirings/http/http.types.d.ts +14 -1
  43. package/dist/wirings/http/log-http-routes.js +1 -1
  44. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  45. package/dist/wirings/mcp/mcp-runner.js +21 -21
  46. package/dist/wirings/queue/queue-runner.js +6 -6
  47. package/dist/wirings/rpc/index.d.ts +1 -1
  48. package/dist/wirings/rpc/index.js +1 -1
  49. package/dist/wirings/rpc/rpc-runner.d.ts +7 -8
  50. package/dist/wirings/rpc/rpc-runner.js +62 -14
  51. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  52. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  53. package/dist/wirings/scheduler/scheduler-runner.js +5 -5
  54. package/dist/wirings/trigger/index.d.ts +2 -0
  55. package/dist/wirings/trigger/index.js +2 -0
  56. package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
  57. package/dist/wirings/trigger/trigger-runner.js +57 -0
  58. package/dist/wirings/trigger/trigger.types.d.ts +42 -0
  59. package/dist/wirings/trigger/trigger.types.js +1 -0
  60. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  61. package/dist/wirings/workflow/dsl/index.js +4 -0
  62. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
  63. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  64. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  65. package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
  66. package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
  67. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  68. package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
  69. package/dist/wirings/workflow/graph/graph-runner.js +452 -0
  70. package/dist/wirings/workflow/graph/index.d.ts +3 -0
  71. package/dist/wirings/workflow/graph/index.js +3 -0
  72. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
  73. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  74. package/dist/wirings/workflow/index.d.ts +7 -12
  75. package/dist/wirings/workflow/index.js +6 -11
  76. package/dist/wirings/workflow/pikku-workflow-service.d.ts +96 -6
  77. package/dist/wirings/workflow/pikku-workflow-service.js +230 -103
  78. package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
  79. package/dist/wirings/workflow/wire-workflow.js +53 -0
  80. package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
  81. package/dist/wirings/workflow/workflow-utils.js +66 -0
  82. package/dist/wirings/workflow/workflow.types.d.ts +133 -211
  83. package/package.json +10 -1
  84. package/src/errors/error-handler.ts +3 -3
  85. package/src/function/function-runner.test.ts +1 -1
  86. package/src/function/function-runner.ts +86 -16
  87. package/src/function/functions.types.ts +126 -4
  88. package/src/index.ts +10 -5
  89. package/src/middleware-runner.ts +16 -9
  90. package/src/permissions.test.ts +28 -86
  91. package/src/permissions.ts +21 -80
  92. package/src/pikku-state.ts +156 -201
  93. package/src/schema.ts +42 -13
  94. package/src/services/workflow-service.ts +74 -0
  95. package/src/types/core.types.ts +12 -3
  96. package/src/types/state.types.ts +195 -0
  97. package/src/utils.ts +55 -0
  98. package/src/wirings/channel/channel-handler.ts +1 -1
  99. package/src/wirings/channel/channel-runner.ts +5 -5
  100. package/src/wirings/channel/local/local-channel-runner.test.ts +3 -1
  101. package/src/wirings/channel/log-channels.ts +1 -1
  102. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -2
  103. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  104. package/src/wirings/cli/cli-runner.test.ts +19 -19
  105. package/src/wirings/cli/cli-runner.ts +10 -9
  106. package/src/wirings/cli/cli.types.ts +1 -0
  107. package/src/wirings/forge-node/forge-node.types.ts +135 -0
  108. package/src/wirings/forge-node/index.ts +1 -0
  109. package/src/wirings/http/http-runner.test.ts +2 -2
  110. package/src/wirings/http/http-runner.ts +30 -13
  111. package/src/wirings/http/http.types.ts +14 -0
  112. package/src/wirings/http/log-http-routes.ts +1 -1
  113. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  114. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  115. package/src/wirings/mcp/mcp-runner.ts +21 -21
  116. package/src/wirings/queue/queue-runner.test.ts +19 -19
  117. package/src/wirings/queue/queue-runner.ts +6 -6
  118. package/src/wirings/rpc/index.ts +1 -1
  119. package/src/wirings/rpc/rpc-runner.ts +88 -22
  120. package/src/wirings/rpc/rpc-types.ts +8 -0
  121. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  122. package/src/wirings/scheduler/scheduler-runner.test.ts +27 -27
  123. package/src/wirings/scheduler/scheduler-runner.ts +5 -5
  124. package/src/wirings/trigger/index.ts +2 -0
  125. package/src/wirings/trigger/trigger-runner.ts +96 -0
  126. package/src/wirings/trigger/trigger.types.ts +56 -0
  127. package/src/wirings/workflow/dsl/index.ts +30 -0
  128. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
  129. package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
  130. package/src/wirings/workflow/graph/graph-node.ts +227 -0
  131. package/src/wirings/workflow/graph/graph-runner.ts +694 -0
  132. package/src/wirings/workflow/graph/index.ts +3 -0
  133. package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
  134. package/src/wirings/workflow/index.ts +53 -26
  135. package/src/wirings/workflow/pikku-workflow-service.ts +333 -117
  136. package/src/wirings/workflow/wire-workflow.ts +94 -0
  137. package/src/wirings/workflow/workflow-utils.ts +120 -0
  138. package/src/wirings/workflow/workflow.types.ts +166 -277
  139. package/tsconfig.tsbuildinfo +1 -1
  140. package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
  141. package/dist/wirings/workflow/workflow-runner.js +0 -65
  142. package/src/function/function-runner.ts.bak +0 -188
  143. package/src/wirings/workflow/workflow-runner.ts +0 -72
@@ -8,7 +8,7 @@ import { freezeDedupe } from './utils.js';
8
8
  * @param wire - The wire object containing request/response context and session.
9
9
  * @returns A promise that resolves to void.
10
10
  */
11
- export const verifyPermissions = async (permissions, services, data, wire) => {
11
+ const verifyPermissions = async (permissions, services, data, wire) => {
12
12
  if (!permissions) {
13
13
  return true;
14
14
  }
@@ -33,27 +33,6 @@ export const verifyPermissions = async (permissions, services, data, wire) => {
33
33
  }
34
34
  return false;
35
35
  };
36
- /**
37
- * Registers a single permission function by name in the global permission store.
38
- *
39
- * This function is used by CLI-generated code to register permission functions
40
- * that can be referenced by name in metadata. It stores permissions in a special
41
- * namespace to avoid conflicts with tag-based permissions.
42
- *
43
- * @param {string} name - The unique name (pikkuFuncName) of the permission function.
44
- * @param {CorePikkuPermission} permission - The permission function to register.
45
- *
46
- * @example
47
- * ```typescript
48
- * // Called by CLI-generated pikku-permissions.gen.ts
49
- * registerPermission('adminPermission_src_permissions_ts_10_5', adminPermission)
50
- * registerPermission('readPermission_src_permissions_ts_20_10', readPermission)
51
- * ```
52
- */
53
- export const registerPermission = (name, permission) => {
54
- const permissionStore = pikkuState('misc', 'permissions');
55
- permissionStore[name] = [permission];
56
- };
57
36
  /**
58
37
  * Retrieves a registered permission function by its name.
59
38
  *
@@ -65,8 +44,8 @@ export const registerPermission = (name, permission) => {
65
44
  *
66
45
  * @internal
67
46
  */
68
- export const getPermissionByName = (name) => {
69
- const permissionStore = pikkuState('misc', 'permissions');
47
+ const getPermissionByName = (name) => {
48
+ const permissionStore = pikkuState(null, 'misc', 'permissions');
70
49
  const permission = permissionStore[name];
71
50
  if (Array.isArray(permission) && permission.length === 1) {
72
51
  return permission[0];
@@ -101,50 +80,14 @@ export const getPermissionByName = (name) => {
101
80
  * ])
102
81
  * ```
103
82
  */
104
- export const addPermission = (tag, permissions) => {
105
- const tagGroups = pikkuState('permissions', 'tagGroup');
83
+ export const addPermission = (tag, permissions, packageName = null) => {
84
+ const tagGroups = pikkuState(packageName, 'permissions', 'tagGroup');
106
85
  if (tagGroups[tag]) {
107
86
  throw new Error(`Permissions for tag '${tag}' already exist. Use a different tag or remove the existing permissions first.`);
108
87
  }
109
88
  tagGroups[tag] = permissions;
110
89
  return permissions;
111
90
  };
112
- const EMPTY = [];
113
- /**
114
- * Retrieves permissions for a given set of tags.
115
- *
116
- * This function looks up all permissions registered for any of the provided tags
117
- * and returns them as a flattened array.
118
- *
119
- * @param {string[]} tags - Array of tags to look up permissions for.
120
- * @returns {any[]} Array of permission functions that apply to the given tags.
121
- *
122
- * @example
123
- * ```typescript
124
- * // Get all permissions for tags 'api' and 'auth'
125
- * const permissions = getPermissionsForTags(['api', 'auth'])
126
- * ```
127
- */
128
- export const getPermissionsForTags = (tags) => {
129
- if (!tags || tags.length === 0) {
130
- return EMPTY;
131
- }
132
- const permissionsStore = pikkuState('permissions', 'tagGroup');
133
- const applicablePermissions = [];
134
- // Collect permissions for all matching tags
135
- for (const tag of new Set(tags)) {
136
- const tagPermissions = permissionsStore[tag];
137
- if (tagPermissions) {
138
- if (Array.isArray(tagPermissions)) {
139
- applicablePermissions.push(...tagPermissions);
140
- }
141
- else {
142
- applicablePermissions.push(tagPermissions);
143
- }
144
- }
145
- }
146
- return applicablePermissions;
147
- };
148
91
  const combinedPermissionsCache = {
149
92
  http: {},
150
93
  rpc: {},
@@ -179,7 +122,7 @@ const combinedPermissionsCache = {
179
122
  * })
180
123
  * ```
181
124
  */
182
- export const combinePermissions = (wireType, uid, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, } = {}) => {
125
+ const combinePermissions = (wireType, uid, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, packageName = null, } = {}) => {
183
126
  if (combinedPermissionsCache[wireType][uid]) {
184
127
  return combinedPermissionsCache[wireType][uid];
185
128
  }
@@ -189,7 +132,7 @@ export const combinePermissions = (wireType, uid, { wireInheritedPermissions, wi
189
132
  for (const meta of wireInheritedPermissions) {
190
133
  if (meta.type === 'http') {
191
134
  // Look up HTTP permission group from pikkuState
192
- const group = pikkuState('permissions', 'httpGroup')[meta.route];
135
+ const group = pikkuState(packageName, 'permissions', 'httpGroup')[meta.route];
193
136
  if (group) {
194
137
  if (Array.isArray(group)) {
195
138
  resolved.push(...group);
@@ -201,7 +144,7 @@ export const combinePermissions = (wireType, uid, { wireInheritedPermissions, wi
201
144
  }
202
145
  else if (meta.type === 'tag') {
203
146
  // Look up tag permission group from pikkuState
204
- const group = pikkuState('permissions', 'tagGroup')[meta.tag];
147
+ const group = pikkuState(packageName, 'permissions', 'tagGroup')[meta.tag];
205
148
  if (group) {
206
149
  if (Array.isArray(group)) {
207
150
  resolved.push(...group);
@@ -234,7 +177,7 @@ export const combinePermissions = (wireType, uid, { wireInheritedPermissions, wi
234
177
  for (const meta of funcInheritedPermissions) {
235
178
  if (meta.type === 'tag') {
236
179
  // Look up tag permission group from pikkuState
237
- const group = pikkuState('permissions', 'tagGroup')[meta.tag];
180
+ const group = pikkuState(packageName, 'permissions', 'tagGroup')[meta.tag];
238
181
  if (group) {
239
182
  if (Array.isArray(group)) {
240
183
  resolved.push(...group);
@@ -264,13 +207,14 @@ export const combinePermissions = (wireType, uid, { wireInheritedPermissions, wi
264
207
  * Runs permission checks using combined permissions from all sources.
265
208
  * Combines permissions from wire and function levels, then validates them.
266
209
  */
267
- export const runPermissions = async (wireType, uid, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, services, wire, data, }) => {
210
+ export const runPermissions = async (wireType, uid, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, services, wire, data, packageName = null, }) => {
268
211
  // Combine all permissions: wireInheritedPermissions → wirePermissions → funcInheritedPermissions → funcPermissions
269
212
  const allPermissions = combinePermissions(wireType, uid, {
270
213
  wireInheritedPermissions,
271
214
  wirePermissions,
272
215
  funcInheritedPermissions,
273
216
  funcPermissions,
217
+ packageName,
274
218
  });
275
219
  // Check all combined permissions - at least one must pass if any exist
276
220
  if (allPermissions.length > 0) {
@@ -1,106 +1,34 @@
1
- import { ChannelsMeta, CoreChannel } from './wirings/channel/channel.types.js';
2
- import { CoreHTTPFunctionWiring, HTTPMethod, HTTPWiringsMeta } from './wirings/http/http.types.js';
3
- import { FunctionsMeta, CorePikkuMiddleware, CorePikkuMiddlewareGroup, FunctionServicesMeta } from './types/core.types.js';
4
- import { CoreScheduledTask, ScheduledTasksMeta } from './wirings/scheduler/scheduler.types.js';
5
- import { ErrorDetails, PikkuError } from './errors/error-handler.js';
6
- import { CorePermissionGroup, CorePikkuFunctionConfig, CorePikkuPermission } from './function/functions.types.js';
7
- import { QueueWorkersMeta, CoreQueueWorker } from './wirings/queue/queue.types.js';
8
- import { CoreMCPResource, CoreMCPTool, CoreMCPPrompt, MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from './wirings/mcp/mcp.types.js';
9
- import { CLIMeta, CLIProgramState } from './wirings/cli/cli.types.js';
10
- import { CoreWorkflow, WorkflowsMeta } from './wirings/workflow/workflow.types.js';
11
- interface PikkuState {
12
- function: {
13
- meta: FunctionsMeta;
14
- functions: Map<string, CorePikkuFunctionConfig<any, any>>;
15
- };
16
- rpc: {
17
- meta: Record<string, string>;
18
- files: Map<string, {
19
- exportedName: string;
20
- path: string;
21
- }>;
22
- };
23
- http: {
24
- middleware: Map<string, CorePikkuMiddleware<any, any>[]>;
25
- permissions: Map<string, CorePermissionGroup | CorePikkuPermission[]>;
26
- routes: Map<HTTPMethod, Map<string, CoreHTTPFunctionWiring<any, any, any>>>;
27
- meta: HTTPWiringsMeta;
28
- };
29
- channel: {
30
- channels: Map<string, CoreChannel<any, any>>;
31
- meta: ChannelsMeta;
32
- };
33
- scheduler: {
34
- tasks: Map<string, CoreScheduledTask>;
35
- meta: ScheduledTasksMeta;
36
- };
37
- queue: {
38
- registrations: Map<string, CoreQueueWorker>;
39
- meta: QueueWorkersMeta;
40
- };
41
- workflows: {
42
- registrations: Map<string, CoreWorkflow>;
43
- meta: WorkflowsMeta;
44
- };
45
- mcp: {
46
- resources: Map<string, CoreMCPResource>;
47
- resourcesMeta: MCPResourceMeta;
48
- tools: Map<string, CoreMCPTool>;
49
- toolsMeta: MCPToolMeta;
50
- prompts: Map<string, CoreMCPPrompt>;
51
- promptsMeta: MCPPromptMeta;
52
- };
53
- cli: {
54
- meta: CLIMeta | Record<string, any>;
55
- programs: Record<string, CLIProgramState>;
56
- };
57
- middleware: {
58
- tagGroup: Record<string, CorePikkuMiddlewareGroup>;
59
- httpGroup: Record<string, CorePikkuMiddlewareGroup>;
60
- tagGroupMeta: Record<string, {
61
- exportName: string | null;
62
- sourceFile: string;
63
- position: number;
64
- services: FunctionServicesMeta;
65
- middlewareCount: number;
66
- isFactory: boolean;
67
- }>;
68
- httpGroupMeta: Record<string, {
69
- exportName: string | null;
70
- sourceFile: string;
71
- position: number;
72
- services: FunctionServicesMeta;
73
- middlewareCount: number;
74
- isFactory: boolean;
75
- }>;
76
- };
77
- permissions: {
78
- tagGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
79
- httpGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
80
- tagGroupMeta: Record<string, {
81
- exportName: string | null;
82
- sourceFile: string;
83
- position: number;
84
- services: FunctionServicesMeta;
85
- permissionCount: number;
86
- isFactory: boolean;
87
- }>;
88
- httpGroupMeta: Record<string, {
89
- exportName: string | null;
90
- sourceFile: string;
91
- position: number;
92
- services: FunctionServicesMeta;
93
- permissionCount: number;
94
- isFactory: boolean;
95
- }>;
96
- };
97
- misc: {
98
- errors: Map<PikkuError, ErrorDetails>;
99
- schemas: Map<string, any>;
100
- middleware: Record<string, CorePikkuMiddleware[]>;
101
- permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
102
- };
1
+ import { PikkuPackageState } from './index.js';
2
+ declare global {
3
+ var pikkuState: Map<string, PikkuPackageState> | undefined;
103
4
  }
5
+ /**
6
+ * Get or set package-scoped pikku state
7
+ *
8
+ * @param packageName - Package name (null for main package, '@scope/package' for external packages)
9
+ * @param type - State category (function, rpc, http, etc.)
10
+ * @param content - Content key within the category
11
+ * @param value - Optional value to set
12
+ * @returns The current value of the state
13
+ *
14
+ * @example
15
+ * // Main package
16
+ * pikkuState(null, 'function', 'functions').get(funcName)
17
+ *
18
+ * // External package
19
+ * pikkuState('@acme/stripe-functions', 'rpc', 'meta')
20
+ */
21
+ export declare const pikkuState: <Type extends keyof PikkuPackageState, Content extends keyof PikkuPackageState[Type]>(packageName: string | null, type: Type, content: Content, value?: PikkuPackageState[Type][Content]) => PikkuPackageState[Type][Content];
22
+ /**
23
+ * Initialize state for a new package
24
+ */
25
+ export declare const initializePikkuState: (packageName: string) => void;
104
26
  export declare const resetPikkuState: () => void;
105
- export declare const pikkuState: <Type extends keyof PikkuState, Content extends keyof PikkuState[Type]>(type: Type, content: Content, value?: PikkuState[Type][Content]) => PikkuState[Type][Content];
106
- export {};
27
+ /**
28
+ * Register service factories for an external package.
29
+ * These factories are used to create services when the package's functions are invoked.
30
+ *
31
+ * @param packageName - The package name (e.g., '@pikku/templates-function-external')
32
+ * @param factories - The service factory functions
33
+ */
34
+ export declare const addPackageServiceFactories: (packageName: string, factories: NonNullable<PikkuPackageState["package"]["factories"]>) => void;
@@ -1,72 +1,146 @@
1
- export const resetPikkuState = () => {
2
- globalThis.pikkuState = {
3
- function: {
4
- meta: {},
5
- functions: new Map(),
6
- },
7
- rpc: {
8
- meta: {},
9
- files: new Map(),
10
- },
11
- http: {
12
- permissions: new Map(),
13
- routes: new Map(),
14
- meta: {},
15
- },
16
- channel: {
17
- channels: new Map(),
18
- meta: {},
19
- },
20
- scheduler: {
21
- tasks: new Map(),
22
- meta: [],
23
- },
24
- queue: {
25
- registrations: new Map(),
26
- meta: {},
27
- },
28
- workflows: {
29
- registrations: new Map(),
30
- meta: {},
31
- },
32
- mcp: {
33
- resources: new Map(),
34
- resourcesMeta: {},
35
- tools: new Map(),
36
- toolsMeta: {},
37
- prompts: new Map(),
38
- promptsMeta: {},
39
- },
40
- cli: {
41
- meta: { programs: {}, renderers: {} },
42
- programs: {},
43
- },
44
- middleware: {
45
- tagGroup: {},
46
- httpGroup: {},
47
- tagGroupMeta: {},
48
- httpGroupMeta: {},
49
- },
50
- permissions: {
51
- tagGroup: {},
52
- httpGroup: {},
53
- tagGroupMeta: {},
54
- httpGroupMeta: {},
55
- },
56
- misc: {
57
- errors: globalThis.pikkuState?.misc?.errors || new Map(),
58
- schemas: new Map(),
59
- middleware: {},
60
- permissions: {},
1
+ /**
2
+ * Get or set package-scoped pikku state
3
+ *
4
+ * @param packageName - Package name (null for main package, '@scope/package' for external packages)
5
+ * @param type - State category (function, rpc, http, etc.)
6
+ * @param content - Content key within the category
7
+ * @param value - Optional value to set
8
+ * @returns The current value of the state
9
+ *
10
+ * @example
11
+ * // Main package
12
+ * pikkuState(null, 'function', 'functions').get(funcName)
13
+ *
14
+ * // External package
15
+ * pikkuState('@acme/stripe-functions', 'rpc', 'meta')
16
+ */
17
+ export const pikkuState = (packageName, type, content, value) => {
18
+ const resolvedPackageName = packageName ?? '__main__';
19
+ // Initialize package state if it doesn't exist
20
+ if (!globalThis.pikkuState ||
21
+ !globalThis.pikkuState.has(resolvedPackageName)) {
22
+ initializePikkuState(resolvedPackageName);
23
+ }
24
+ const packageState = globalThis.pikkuState.get(resolvedPackageName);
25
+ if (value !== undefined) {
26
+ packageState[type][content] = value;
27
+ }
28
+ return packageState[type][content];
29
+ };
30
+ const createEmptyPackageState = () => ({
31
+ function: {
32
+ meta: {},
33
+ functions: new Map(),
34
+ },
35
+ rpc: {
36
+ meta: {},
37
+ files: new Map(),
38
+ externalPackages: new Map(),
39
+ },
40
+ http: {
41
+ middleware: new Map(),
42
+ permissions: new Map(),
43
+ routes: new Map(),
44
+ meta: {
45
+ post: {},
46
+ get: {},
47
+ delete: {},
48
+ patch: {},
49
+ head: {},
50
+ put: {},
51
+ options: {},
61
52
  },
62
- };
53
+ },
54
+ channel: {
55
+ channels: new Map(),
56
+ meta: {},
57
+ },
58
+ scheduler: {
59
+ tasks: new Map(),
60
+ meta: [],
61
+ },
62
+ queue: {
63
+ registrations: new Map(),
64
+ meta: {},
65
+ },
66
+ workflows: {
67
+ registrations: new Map(),
68
+ graphRegistrations: new Map(),
69
+ wirings: new Map(),
70
+ graphWirings: new Map(),
71
+ meta: {},
72
+ },
73
+ trigger: {
74
+ triggers: new Map(),
75
+ meta: {},
76
+ },
77
+ mcp: {
78
+ resources: new Map(),
79
+ resourcesMeta: {},
80
+ tools: new Map(),
81
+ toolsMeta: {},
82
+ prompts: new Map(),
83
+ promptsMeta: {},
84
+ },
85
+ cli: {
86
+ meta: { programs: {}, renderers: {} },
87
+ programs: {},
88
+ },
89
+ middleware: {
90
+ tagGroup: {},
91
+ httpGroup: {},
92
+ tagGroupMeta: {},
93
+ httpGroupMeta: {},
94
+ },
95
+ permissions: {
96
+ tagGroup: {},
97
+ httpGroup: {},
98
+ tagGroupMeta: {},
99
+ httpGroupMeta: {},
100
+ },
101
+ misc: {
102
+ errors: new Map(),
103
+ schemas: new Map(),
104
+ middleware: {},
105
+ permissions: {},
106
+ },
107
+ package: {
108
+ factories: null,
109
+ singletonServices: null,
110
+ },
111
+ });
112
+ /**
113
+ * Initialize state for a new package
114
+ */
115
+ export const initializePikkuState = (packageName) => {
116
+ if (!globalThis.pikkuState) {
117
+ globalThis.pikkuState = new Map();
118
+ }
119
+ if (!globalThis.pikkuState.has(packageName)) {
120
+ globalThis.pikkuState.set(packageName, createEmptyPackageState());
121
+ }
122
+ };
123
+ export const resetPikkuState = () => {
124
+ // Preserve the errors map before resetting
125
+ const existingErrors = globalThis.pikkuState?.get('__main__')?.misc.errors;
126
+ globalThis.pikkuState = new Map();
127
+ initializePikkuState('__main__');
128
+ // Restore the errors map if it existed
129
+ if (existingErrors) {
130
+ const mainState = globalThis.pikkuState.get('__main__');
131
+ mainState.misc.errors = existingErrors;
132
+ }
63
133
  };
64
134
  if (!globalThis.pikkuState) {
65
135
  resetPikkuState();
66
136
  }
67
- export const pikkuState = (type, content, value) => {
68
- if (value) {
69
- globalThis.pikkuState[type][content] = value;
70
- }
71
- return globalThis.pikkuState[type][content];
137
+ /**
138
+ * Register service factories for an external package.
139
+ * These factories are used to create services when the package's functions are invoked.
140
+ *
141
+ * @param packageName - The package name (e.g., '@pikku/templates-function-external')
142
+ * @param factories - The service factory functions
143
+ */
144
+ export const addPackageServiceFactories = (packageName, factories) => {
145
+ pikkuState(packageName, 'package', 'factories', factories);
72
146
  };
package/dist/schema.d.ts CHANGED
@@ -1,23 +1,25 @@
1
1
  import { Logger } from './services/logger.js';
2
2
  import { SchemaService } from './services/schema-service.js';
3
3
  /**
4
- * Adds a schema to the global schemas map.
4
+ * Adds a schema to the schemas map for a specific package.
5
5
  * @param name - The name of the schema.
6
6
  * @param value - The schema value.
7
+ * @param packageName - The package name (null for main package, '@scope/package' for external packages).
7
8
  * @ignore
8
9
  */
9
- export declare const addSchema: (name: string, value: any) => void;
10
+ export declare const addSchema: (name: string, value: any, packageName?: string | null) => void;
10
11
  /**
11
- * Retrieves a schema from the global schemas map.
12
+ * Retrieves a schema from the schemas map for a specific package.
12
13
  * @param name - The name of the schema.
14
+ * @param packageName - The package name (null for main package, '@scope/package' for external packages).
13
15
  * @returns The schema value or undefined if not found.
14
16
  * @ignore
15
17
  */
16
- export declare const getSchema: (name: string) => Record<string, unknown> | undefined;
18
+ export declare const getSchema: (name: string, packageName?: string | null) => Record<string, unknown> | undefined;
17
19
  /**
18
20
  * Loads a schema and compiles it into a validator.
19
21
  * @param logger - A logger for logging information.
20
22
  */
21
23
  export declare const compileAllSchemas: (logger: Logger, schemaService?: SchemaService) => void;
22
- export declare const coerceTopLevelDataFromSchema: (schemaName: string, data: any) => void;
23
- export declare const validateSchema: (logger: Logger, schemaService: SchemaService | undefined, schemaName: string | undefined | null, data: any) => Promise<void>;
24
+ export declare const coerceTopLevelDataFromSchema: (schemaName: string, data: any, packageName?: string | null) => void;
25
+ export declare const validateSchema: (logger: Logger, schemaService: SchemaService | undefined, schemaName: string | undefined | null, data: any, packageName?: string | null) => Promise<void>;
package/dist/schema.js CHANGED
@@ -1,22 +1,24 @@
1
1
  import { UnprocessableContentError } from './errors/errors.js';
2
2
  import { pikkuState } from './pikku-state.js';
3
3
  /**
4
- * Adds a schema to the global schemas map.
4
+ * Adds a schema to the schemas map for a specific package.
5
5
  * @param name - The name of the schema.
6
6
  * @param value - The schema value.
7
+ * @param packageName - The package name (null for main package, '@scope/package' for external packages).
7
8
  * @ignore
8
9
  */
9
- export const addSchema = (name, value) => {
10
- pikkuState('misc', 'schemas').set(name, value);
10
+ export const addSchema = (name, value, packageName = null) => {
11
+ pikkuState(packageName, 'misc', 'schemas').set(name, value);
11
12
  };
12
13
  /**
13
- * Retrieves a schema from the global schemas map.
14
+ * Retrieves a schema from the schemas map for a specific package.
14
15
  * @param name - The name of the schema.
16
+ * @param packageName - The package name (null for main package, '@scope/package' for external packages).
15
17
  * @returns The schema value or undefined if not found.
16
18
  * @ignore
17
19
  */
18
- export const getSchema = (name) => {
19
- return pikkuState('misc', 'schemas').get(name);
20
+ export const getSchema = (name, packageName = null) => {
21
+ return pikkuState(packageName, 'misc', 'schemas').get(name);
20
22
  };
21
23
  /**
22
24
  * Loads a schema and compiles it into a validator.
@@ -26,19 +28,20 @@ export const compileAllSchemas = (logger, schemaService) => {
26
28
  if (!schemaService) {
27
29
  throw new Error('SchemaService needs to be defined to load schemas');
28
30
  }
29
- const schemas = pikkuState('misc', 'schemas');
31
+ const schemas = pikkuState(null, 'misc', 'schemas');
30
32
  for (const [name, schema] of schemas) {
31
33
  schemaService.compileSchema(name, schema);
32
34
  }
33
35
  validateAllSchemasLoaded(logger, schemaService);
34
36
  };
35
37
  const validateAllSchemasLoaded = (logger, schemaService) => {
36
- const routesMeta = pikkuState('http', 'meta');
38
+ const routesMeta = pikkuState(null, 'http', 'meta');
37
39
  const validators = schemaService.getSchemaNames();
38
40
  const missingSchemas = [];
39
41
  for (const routePaths of Object.values(routesMeta)) {
40
42
  for (const meta of Object.values(routePaths)) {
41
- const inputs = pikkuState('function', 'meta')[meta.pikkuFuncName]?.inputs;
43
+ const inputs = pikkuState(null, 'function', 'meta')[meta.pikkuFuncName]
44
+ ?.inputs;
42
45
  const input = inputs?.[0];
43
46
  if (!input || validators.has(input)) {
44
47
  continue;
@@ -55,8 +58,8 @@ const validateAllSchemasLoaded = (logger, schemaService) => {
55
58
  logger.info('All schemas loaded');
56
59
  }
57
60
  };
58
- export const coerceTopLevelDataFromSchema = (schemaName, data) => {
59
- const schema = pikkuState('misc', 'schemas').get(schemaName);
61
+ export const coerceTopLevelDataFromSchema = (schemaName, data, packageName = null) => {
62
+ const schema = pikkuState(packageName, 'misc', 'schemas').get(schemaName);
60
63
  for (const key in schema.properties) {
61
64
  const property = schema.properties[key];
62
65
  if (typeof property === 'boolean') {
@@ -74,7 +77,7 @@ export const coerceTopLevelDataFromSchema = (schemaName, data) => {
74
77
  }
75
78
  }
76
79
  };
77
- export const validateSchema = async (logger, schemaService, schemaName, data) => {
80
+ export const validateSchema = async (logger, schemaService, schemaName, data, packageName = null) => {
78
81
  if (schemaService) {
79
82
  if (!schemaName) {
80
83
  if (data && (data.length > 0 || Object.keys(data).length > 0)) {
@@ -85,7 +88,16 @@ export const validateSchema = async (logger, schemaService, schemaName, data) =>
85
88
  return;
86
89
  }
87
90
  }
88
- const schema = pikkuState('misc', 'schemas').get(schemaName);
91
+ logger.debug(`[validateSchema] Validating schema '${schemaName}' for package '${packageName ?? 'main'}' with data:`, JSON.stringify(data));
92
+ const schemas = pikkuState(packageName, 'misc', 'schemas');
93
+ const schema = schemas.get(schemaName);
94
+ if (schema === undefined) {
95
+ const availableSchemas = Array.from(schemas.keys());
96
+ logger.error(`Schema '${schemaName}' not found for package '${packageName ?? 'main'}'. Available schemas: ${availableSchemas.join(', ') || '(none)'}`);
97
+ }
98
+ else {
99
+ logger.debug(`[validateSchema] Found schema '${schemaName}':`, JSON.stringify(schema));
100
+ }
89
101
  await schemaService.compileSchema(schemaName, schema);
90
102
  await schemaService.validateSchema(schemaName, data);
91
103
  }
@@ -0,0 +1,38 @@
1
+ import { SerializedError, CoreSingletonServices, CreateWireServices, CoreConfig } from '../types/core.types.js';
2
+ import { WorkflowRun, StepState, WorkflowStatus } from '../wirings/workflow/workflow.types.js';
3
+ /**
4
+ * Interface for workflow orchestration
5
+ * Handles workflow execution, replay, orchestration logic, and run-level state
6
+ */
7
+ export interface WorkflowService {
8
+ createRun(workflowName: string, input: any, inline?: boolean): Promise<string>;
9
+ getRun(id: string): Promise<WorkflowRun | null>;
10
+ getRunHistory(runId: string): Promise<Array<StepState & {
11
+ stepName: string;
12
+ }>>;
13
+ updateRunStatus(id: string, status: WorkflowStatus, output?: any, error?: SerializedError): Promise<void>;
14
+ withRunLock<T>(id: string, fn: () => Promise<T>): Promise<T>;
15
+ close(): Promise<void>;
16
+ resumeWorkflow(runId: string): Promise<void>;
17
+ setServices(singletonServices: CoreSingletonServices, createWireServices: CreateWireServices, config: CoreConfig): void;
18
+ startWorkflow<I>(name: string, input: I, rpcService: any, options?: {
19
+ inline?: boolean;
20
+ startNode?: string;
21
+ }): Promise<{
22
+ runId: string;
23
+ }>;
24
+ runWorkflowJob(runId: string, rpcService: any): Promise<void>;
25
+ orchestrateWorkflow(runId: string, rpcService: any): Promise<void>;
26
+ executeWorkflowSleepCompleted(runId: string, stepId: string): Promise<void>;
27
+ insertStepState(runId: string, stepName: string, rpcName: string, data: any, stepOptions?: {
28
+ retries?: number;
29
+ retryDelay?: string | number;
30
+ }): Promise<StepState>;
31
+ getStepState(runId: string, stepName: string): Promise<StepState>;
32
+ setStepRunning(stepId: string): Promise<void>;
33
+ setStepScheduled(stepId: string): Promise<void>;
34
+ setStepResult(stepId: string, result: any): Promise<void>;
35
+ setStepError(stepId: string, error: Error): Promise<void>;
36
+ createRetryAttempt(stepId: string, status: 'pending' | 'running'): Promise<StepState>;
37
+ executeWorkflowStep(runId: string, stepName: string, rpcName: string | null, data: any, rpcService: any): Promise<void>;
38
+ }
@@ -0,0 +1 @@
1
+ export {};