@jami-studio/core 0.92.27 → 0.92.29

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 (56) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +34 -0
  3. package/corpus/core/package.json +2 -1
  4. package/corpus/core/src/deploy/build.ts +120 -2
  5. package/corpus/core/src/event-bus/bus.ts +138 -140
  6. package/corpus/core/src/event-bus/registry.ts +81 -79
  7. package/corpus/core/src/file-upload/registry.ts +135 -125
  8. package/corpus/core/src/notifications/registry.ts +218 -216
  9. package/corpus/core/src/private-blob/registry.ts +246 -242
  10. package/corpus/core/src/secrets/register.ts +132 -129
  11. package/corpus/core/src/shared/global-scope.ts +75 -0
  12. package/corpus/core/src/sharing/registry.ts +193 -194
  13. package/corpus/core/src/tracking/providers.ts +425 -422
  14. package/corpus/core/src/tracking/registry.ts +102 -102
  15. package/dist/collab/routes.d.ts +1 -1
  16. package/dist/deploy/build.d.ts +44 -0
  17. package/dist/deploy/build.d.ts.map +1 -1
  18. package/dist/deploy/build.js +91 -2
  19. package/dist/deploy/build.js.map +1 -1
  20. package/dist/event-bus/bus.d.ts.map +1 -1
  21. package/dist/event-bus/bus.js +8 -6
  22. package/dist/event-bus/bus.js.map +1 -1
  23. package/dist/event-bus/registry.d.ts.map +1 -1
  24. package/dist/event-bus/registry.js +10 -6
  25. package/dist/event-bus/registry.js.map +1 -1
  26. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  27. package/dist/file-upload/registry.d.ts.map +1 -1
  28. package/dist/file-upload/registry.js +28 -8
  29. package/dist/file-upload/registry.js.map +1 -1
  30. package/dist/notifications/registry.d.ts.map +1 -1
  31. package/dist/notifications/registry.js +6 -5
  32. package/dist/notifications/registry.js.map +1 -1
  33. package/dist/observability/routes.d.ts +5 -5
  34. package/dist/private-blob/registry.d.ts.map +1 -1
  35. package/dist/private-blob/registry.js +18 -13
  36. package/dist/private-blob/registry.js.map +1 -1
  37. package/dist/progress/routes.d.ts +1 -1
  38. package/dist/resources/handlers.d.ts +2 -2
  39. package/dist/secrets/register.d.ts.map +1 -1
  40. package/dist/secrets/register.js +11 -7
  41. package/dist/secrets/register.js.map +1 -1
  42. package/dist/secrets/routes.d.ts +9 -9
  43. package/dist/shared/global-scope.d.ts +55 -0
  44. package/dist/shared/global-scope.d.ts.map +1 -0
  45. package/dist/shared/global-scope.js +70 -0
  46. package/dist/shared/global-scope.js.map +1 -0
  47. package/dist/sharing/registry.d.ts.map +1 -1
  48. package/dist/sharing/registry.js +2 -16
  49. package/dist/sharing/registry.js.map +1 -1
  50. package/dist/tracking/providers.d.ts.map +1 -1
  51. package/dist/tracking/providers.js +11 -9
  52. package/dist/tracking/providers.js.map +1 -1
  53. package/dist/tracking/registry.d.ts.map +1 -1
  54. package/dist/tracking/registry.js +5 -5
  55. package/dist/tracking/registry.js.map +1 -1
  56. package/package.json +2 -1
@@ -1,79 +1,81 @@
1
- /**
2
- * In-process registry of event definitions.
3
- *
4
- * Integrations and templates call `registerEvent()` at module load to declare
5
- * the event types they emit. The bus uses these definitions to validate
6
- * payloads, and the Automations UI lists them so users can build triggers.
7
- */
8
-
9
- import { z } from "zod";
10
-
11
- import type { EventDefinition } from "./types.js";
12
-
13
- // Pin to globalThis so multiple ESM graphs (dev-mode Vite + Nitro, symlinks,
14
- // dist/ vs src/) share a single registry. Same pattern as secrets/register.ts.
15
- const REGISTRY_KEY = Symbol.for("@agent-native/core/event-bus.registry");
16
- interface GlobalWithRegistry {
17
- [REGISTRY_KEY]?: Map<string, EventDefinition>;
18
- }
19
- const registry: Map<string, EventDefinition> = ((
20
- globalThis as unknown as GlobalWithRegistry
21
- )[REGISTRY_KEY] ??= new Map());
22
-
23
- /**
24
- * Register (or replace) an event definition.
25
- *
26
- * Subsequent registrations with the same `name` replace the previous
27
- * definition — later plugins can override built-in defaults.
28
- */
29
- export function registerEvent(def: EventDefinition): void {
30
- if (!def || typeof def.name !== "string" || !def.name) {
31
- throw new Error("registerEvent: def.name is required");
32
- }
33
- if (typeof def.description !== "string" || !def.description) {
34
- throw new Error("registerEvent: def.description is required");
35
- }
36
- if (!def.payloadSchema) {
37
- throw new Error("registerEvent: def.payloadSchema is required");
38
- }
39
- registry.set(def.name, def);
40
- }
41
-
42
- /** Return all registered events in registration order. */
43
- export function listEvents(): EventDefinition[] {
44
- return Array.from(registry.values());
45
- }
46
-
47
- /** Look up a single registered event by name. */
48
- export function getEvent(name: string): EventDefinition | undefined {
49
- return registry.get(name);
50
- }
51
-
52
- /** Test helper — clears the registry between runs. */
53
- export function __resetEventRegistry(): void {
54
- registry.clear();
55
- registerBuiltInEvents();
56
- }
57
-
58
- function registerBuiltInEvents(): void {
59
- registerEvent({
60
- name: "test.event.fired",
61
- description:
62
- "Developer test eventfired manually from the Automations UI or via the test-event action.",
63
- payloadSchema: z
64
- .object({ data: z.record(z.string(), z.unknown()).optional() })
65
- .optional() as unknown as EventDefinition["payloadSchema"],
66
- });
67
-
68
- registerEvent({
69
- name: "agent.turn.completed",
70
- description: "Fires after the agent completes a conversational turn.",
71
- payloadSchema: z.object({
72
- threadId: z.string().optional(),
73
- turnIndex: z.number().optional(),
74
- model: z.string().optional(),
75
- }) as unknown as EventDefinition["payloadSchema"],
76
- });
77
- }
78
-
79
- registerBuiltInEvents();
1
+ /**
2
+ * In-process registry of event definitions.
3
+ *
4
+ * Integrations and templates call `registerEvent()` at module load to declare
5
+ * the event types they emit. The bus uses these definitions to validate
6
+ * payloads, and the Automations UI lists them so users can build triggers.
7
+ */
8
+
9
+ import { z } from "zod";
10
+
11
+ import { getScopedGlobal } from "../shared/global-scope.js";
12
+ import type { EventDefinition } from "./types.js";
13
+
14
+ // Pin to globalThis so multiple ESM graphs (dev-mode Vite + Nitro, symlinks,
15
+ // dist/ vs src/) share a single registry. Same pattern as secrets/register.ts.
16
+ // Scope-aware + lazily resolved so unified workspace deployments (all apps in
17
+ // one isolate) keep per-app event definitions. See shared/global-scope.
18
+ function getEventRegistry(): Map<string, EventDefinition> {
19
+ return getScopedGlobal(
20
+ "agent-native.event-bus.registry",
21
+ () => new Map<string, EventDefinition>(),
22
+ );
23
+ }
24
+
25
+ /**
26
+ * Register (or replace) an event definition.
27
+ *
28
+ * Subsequent registrations with the same `name` replace the previous
29
+ * definition later plugins can override built-in defaults.
30
+ */
31
+ export function registerEvent(def: EventDefinition): void {
32
+ if (!def || typeof def.name !== "string" || !def.name) {
33
+ throw new Error("registerEvent: def.name is required");
34
+ }
35
+ if (typeof def.description !== "string" || !def.description) {
36
+ throw new Error("registerEvent: def.description is required");
37
+ }
38
+ if (!def.payloadSchema) {
39
+ throw new Error("registerEvent: def.payloadSchema is required");
40
+ }
41
+ getEventRegistry().set(def.name, def);
42
+ }
43
+
44
+ /** Return all registered events in registration order. */
45
+ export function listEvents(): EventDefinition[] {
46
+ return Array.from(getEventRegistry().values());
47
+ }
48
+
49
+ /** Look up a single registered event by name. */
50
+ export function getEvent(name: string): EventDefinition | undefined {
51
+ return getEventRegistry().get(name);
52
+ }
53
+
54
+ /** Test helper — clears the registry between runs. */
55
+ export function __resetEventRegistry(): void {
56
+ getEventRegistry().clear();
57
+ registerBuiltInEvents();
58
+ }
59
+
60
+ function registerBuiltInEvents(): void {
61
+ registerEvent({
62
+ name: "test.event.fired",
63
+ description:
64
+ "Developer test event — fired manually from the Automations UI or via the test-event action.",
65
+ payloadSchema: z
66
+ .object({ data: z.record(z.string(), z.unknown()).optional() })
67
+ .optional() as unknown as EventDefinition["payloadSchema"],
68
+ });
69
+
70
+ registerEvent({
71
+ name: "agent.turn.completed",
72
+ description: "Fires after the agent completes a conversational turn.",
73
+ payloadSchema: z.object({
74
+ threadId: z.string().optional(),
75
+ turnIndex: z.number().optional(),
76
+ model: z.string().optional(),
77
+ }) as unknown as EventDefinition["payloadSchema"],
78
+ });
79
+ }
80
+
81
+ registerBuiltInEvents();
@@ -1,125 +1,135 @@
1
- import { builderFileUploadProvider } from "./builder.js";
2
- import type {
3
- FileUploadInput,
4
- FileUploadProvider,
5
- FileUploadResult,
6
- } from "./types.js";
7
-
8
- // Why globalThis: in dev (Vite HMR) and in some Nitro/Rollup bundle splits,
9
- // this module can be evaluated more than once the plugin file that
10
- // registers a provider lands in one module instance and the request handler
11
- // that reads providers lands in another, so the call site sees an empty map
12
- // even though `registerFileUploadProvider` succeeded. Pinning the singletons
13
- // on `globalThis` guarantees one set of providers per Node process,
14
- // independent of how the bundler split the chunks.
15
- interface FileUploadGlobals {
16
- __agentNativeFileUploadProviders?: Map<string, FileUploadProvider>;
17
- __agentNativeFileUploadWarnedFallback?: { value: boolean };
18
- }
19
- const globals = globalThis as typeof globalThis & FileUploadGlobals;
20
- const providers: Map<string, FileUploadProvider> =
21
- (globals.__agentNativeFileUploadProviders ??= new Map());
22
- const warnedFallbackRef: { value: boolean } =
23
- (globals.__agentNativeFileUploadWarnedFallback ??= { value: false });
24
-
25
- /**
26
- * Register a file upload provider. Call from a server plugin or app
27
- * bootstrap. Idempotent per id — later calls with the same id replace.
28
- */
29
- export function registerFileUploadProvider(provider: FileUploadProvider): void {
30
- providers.set(provider.id, provider);
31
- }
32
-
33
- export function unregisterFileUploadProvider(id: string): void {
34
- providers.delete(id);
35
- }
36
-
37
- export function listFileUploadProviders(): FileUploadProvider[] {
38
- return [...providers.values()];
39
- }
40
-
41
- /**
42
- * Returns the first configured provider, checking user-registered ones first
43
- * and falling back to the built-in Builder.io provider when its env is set.
44
- * Returns `null` when nothing is configured — callers should then use the
45
- * SQL fallback.
46
- */
47
- export function getActiveFileUploadProvider(): FileUploadProvider | null {
48
- for (const provider of providers.values()) {
49
- if (provider.isConfigured()) return provider;
50
- }
51
- if (builderFileUploadProvider.isConfigured()) {
52
- return builderFileUploadProvider;
53
- }
54
- return null;
55
- }
56
-
57
- export async function getActiveFileUploadProviderForRequest(): Promise<FileUploadProvider | null> {
58
- for (const provider of providers.values()) {
59
- if (provider.isConfigured()) return provider;
60
- if (provider.isConfiguredForRequest) {
61
- try {
62
- if (await provider.isConfiguredForRequest()) return provider;
63
- } catch {
64
- // Treat failed scoped credential lookups as unavailable. The upload
65
- // call will surface real provider errors after a provider is selected.
66
- }
67
- }
68
- }
69
- if (builderFileUploadProvider.isConfigured()) {
70
- return builderFileUploadProvider;
71
- }
72
- return null;
73
- }
74
-
75
- /**
76
- * Upload a file via the active provider, or `null` if no provider is
77
- * configured. Callers use `null` as the signal to fall back to SQL
78
- * storage. On the first fallback we log a one-time warning because
79
- * storing files in SQL is not optimal for production.
80
- */
81
- export async function uploadFile(
82
- input: FileUploadInput,
83
- ): Promise<FileUploadResult | null> {
84
- const provider = await getActiveFileUploadProviderForRequest();
85
- // User-registered providers (S3, etc.) may be configured by sync runtime
86
- // state or request-scoped DB secrets. Builder still gets an explicit async
87
- // credential check below because its sync isConfigured() only checks env.
88
- if (provider && provider !== builderFileUploadProvider) {
89
- return provider.upload(input);
90
- }
91
-
92
- // Resolve credentials asynchronously (works when request context is set
93
- // via runWithRequestContext actions always have one via action-routes.ts).
94
- // Two separate try-catch blocks ensure a real upload failure is never
95
- // silently swallowed as a "no credentials" case.
96
- let builderKey: string | null = null;
97
- try {
98
- const { resolveBuilderPrivateKey } =
99
- await import("../server/credential-provider.js");
100
- builderKey = await resolveBuilderPrivateKey();
101
- } catch (err) {
102
- // DB unavailable or credential store not ready can't resolve key.
103
- // Log and fall through to the SQL fallback below.
104
- console.warn(
105
- "[agent-native] Builder credential check failed:",
106
- err instanceof Error ? err.message : String(err),
107
- );
108
- }
109
-
110
- if (builderKey) {
111
- // Credentials confirmed attempt the upload. Real errors (network,
112
- // API, rate-limit) propagate to the caller; do NOT catch them here.
113
- return await builderFileUploadProvider.upload(input);
114
- }
115
-
116
- if (!warnedFallbackRef.value) {
117
- warnedFallbackRef.value = true;
118
- console.warn(
119
- "[agent-native] No file upload provider configured. " +
120
- "Connect or reconnect Builder.io in Settings File uploads, " +
121
- "or register a custom provider (S3, R2, GCS, …) via registerFileUploadProvider().",
122
- );
123
- }
124
- return null;
125
- }
1
+ import { getScopedGlobal } from "../shared/global-scope.js";
2
+ import { builderFileUploadProvider } from "./builder.js";
3
+ import type {
4
+ FileUploadInput,
5
+ FileUploadProvider,
6
+ FileUploadResult,
7
+ } from "./types.js";
8
+
9
+ // Why globalThis: in dev (Vite HMR) and in some Nitro/Rollup bundle splits,
10
+ // this module can be evaluated more than once the plugin file that
11
+ // registers a provider lands in one module instance and the request handler
12
+ // that reads providers lands in another, so the call site sees an empty map
13
+ // even though `registerFileUploadProvider` succeeded. Pinning the singletons
14
+ // on `globalThis` guarantees one set of providers per Node process,
15
+ // independent of how the bundler split the chunks.
16
+ //
17
+ // Why scope-aware + lazy: on a unified workspace deployment every app shares
18
+ // one isolate, so a raw globalThis pin would merge every app's providers into
19
+ // one map (an /assets upload was served by clips' provider). The keys are
20
+ // namespaced per app via `getScopedGlobal`, resolved lazily on every access
21
+ // so the scope id set by the generated worker entry is always honored.
22
+ function getProviders(): Map<string, FileUploadProvider> {
23
+ return getScopedGlobal(
24
+ "agent-native.file-upload.providers",
25
+ () => new Map<string, FileUploadProvider>(),
26
+ );
27
+ }
28
+ function getWarnedFallbackRef(): { value: boolean } {
29
+ return getScopedGlobal("agent-native.file-upload.warned-fallback", () => ({
30
+ value: false,
31
+ }));
32
+ }
33
+
34
+ /**
35
+ * Register a file upload provider. Call from a server plugin or app
36
+ * bootstrap. Idempotent per id — later calls with the same id replace.
37
+ */
38
+ export function registerFileUploadProvider(provider: FileUploadProvider): void {
39
+ getProviders().set(provider.id, provider);
40
+ }
41
+
42
+ export function unregisterFileUploadProvider(id: string): void {
43
+ getProviders().delete(id);
44
+ }
45
+
46
+ export function listFileUploadProviders(): FileUploadProvider[] {
47
+ return [...getProviders().values()];
48
+ }
49
+
50
+ /**
51
+ * Returns the first configured provider, checking user-registered ones first
52
+ * and falling back to the built-in Builder.io provider when its env is set.
53
+ * Returns `null` when nothing is configured — callers should then use the
54
+ * SQL fallback.
55
+ */
56
+ export function getActiveFileUploadProvider(): FileUploadProvider | null {
57
+ for (const provider of getProviders().values()) {
58
+ if (provider.isConfigured()) return provider;
59
+ }
60
+ if (builderFileUploadProvider.isConfigured()) {
61
+ return builderFileUploadProvider;
62
+ }
63
+ return null;
64
+ }
65
+
66
+ export async function getActiveFileUploadProviderForRequest(): Promise<FileUploadProvider | null> {
67
+ for (const provider of getProviders().values()) {
68
+ if (provider.isConfigured()) return provider;
69
+ if (provider.isConfiguredForRequest) {
70
+ try {
71
+ if (await provider.isConfiguredForRequest()) return provider;
72
+ } catch {
73
+ // Treat failed scoped credential lookups as unavailable. The upload
74
+ // call will surface real provider errors after a provider is selected.
75
+ }
76
+ }
77
+ }
78
+ if (builderFileUploadProvider.isConfigured()) {
79
+ return builderFileUploadProvider;
80
+ }
81
+ return null;
82
+ }
83
+
84
+ /**
85
+ * Upload a file via the active provider, or `null` if no provider is
86
+ * configured. Callers use `null` as the signal to fall back to SQL
87
+ * storage. On the first fallback we log a one-time warning because
88
+ * storing files in SQL is not optimal for production.
89
+ */
90
+ export async function uploadFile(
91
+ input: FileUploadInput,
92
+ ): Promise<FileUploadResult | null> {
93
+ const provider = await getActiveFileUploadProviderForRequest();
94
+ // User-registered providers (S3, etc.) may be configured by sync runtime
95
+ // state or request-scoped DB secrets. Builder still gets an explicit async
96
+ // credential check below because its sync isConfigured() only checks env.
97
+ if (provider && provider !== builderFileUploadProvider) {
98
+ return provider.upload(input);
99
+ }
100
+
101
+ // Resolve credentials asynchronously (works when request context is set
102
+ // via runWithRequestContext actions always have one via action-routes.ts).
103
+ // Two separate try-catch blocks ensure a real upload failure is never
104
+ // silently swallowed as a "no credentials" case.
105
+ let builderKey: string | null = null;
106
+ try {
107
+ const { resolveBuilderPrivateKey } =
108
+ await import("../server/credential-provider.js");
109
+ builderKey = await resolveBuilderPrivateKey();
110
+ } catch (err) {
111
+ // DB unavailable or credential store not ready can't resolve key.
112
+ // Log and fall through to the SQL fallback below.
113
+ console.warn(
114
+ "[agent-native] Builder credential check failed:",
115
+ err instanceof Error ? err.message : String(err),
116
+ );
117
+ }
118
+
119
+ if (builderKey) {
120
+ // Credentials confirmed attempt the upload. Real errors (network,
121
+ // API, rate-limit) propagate to the caller; do NOT catch them here.
122
+ return await builderFileUploadProvider.upload(input);
123
+ }
124
+
125
+ const warnedFallbackRef = getWarnedFallbackRef();
126
+ if (!warnedFallbackRef.value) {
127
+ warnedFallbackRef.value = true;
128
+ console.warn(
129
+ "[agent-native] No file upload provider configured. " +
130
+ "Connect or reconnect Builder.io in Settings → File uploads, " +
131
+ "or register a custom provider (S3, R2, GCS, …) via registerFileUploadProvider().",
132
+ );
133
+ }
134
+ return null;
135
+ }