@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,194 +1,193 @@
1
- /**
2
- * Registry of shareable resources.
3
- *
4
- * Each template registers its ownable resource(s) once on module load so the
5
- * framework-level share actions (`share-resource`, `list-resource-shares`,
6
- * etc.) can dispatch to the correct tables.
7
- *
8
- * import { registerShareableResource } from "@agent-native/core/sharing";
9
- * import * as schema from "./schema.js";
10
- *
11
- * registerShareableResource({
12
- * type: "document",
13
- * resourceTable: schema.documents,
14
- * sharesTable: schema.documentShares,
15
- * displayName: "Document",
16
- * titleColumn: "title",
17
- * });
18
- */
19
-
20
- export interface ShareableResourceRegistration {
21
- /** Stable identifier used across actions, UI, and analytics. e.g. "document". */
22
- type: string;
23
- /** Drizzle table for the parent resource (must have ownableColumns()). */
24
- resourceTable: any;
25
- /** Drizzle table produced by createSharesTable(). */
26
- sharesTable: any;
27
- /** Human-readable singular label shown in the share dialog. */
28
- displayName: string;
29
- /**
30
- * Column on the resource table that holds a human-readable title for
31
- * display in the share UI. Default: "title".
32
- */
33
- titleColumn?: string;
34
- /**
35
- * Optional app-relative path to this resource. Used by share notifications
36
- * when the caller does not pass a more specific resourceUrl.
37
- */
38
- getResourcePath?: (resource: any) => string | undefined;
39
- /**
40
- * Drizzle DB accessor from the template's server/db/index.ts. Required —
41
- * the framework-level share actions and access helpers call this to reach
42
- * the right DB instance (schema is template-specific).
43
- */
44
- getDb: () => any;
45
- /**
46
- * When `false`, `visibility: "public"` is rejected by `set-resource-visibility`,
47
- * and `accessFilter` / `resolveAccess` treat any stored public row as private
48
- * (defense in depth only owner + explicit shares grant access).
49
- *
50
- * Use this for resources that execute code or expose privileged data and must
51
- * never be reachable by a random authenticated user. Extensions set this:
52
- * extension HTML runs inside an iframe that calls actions / DB / proxied APIs
53
- * as the *viewer*, so a public extension would be arbitrary code with the
54
- * viewer's credentials.
55
- *
56
- * Default: `true` (matches the historical behavior — most resources can be public).
57
- */
58
- allowPublic?: boolean;
59
- /**
60
- * Optional role granted by a public-by-link read. Most resources should omit
61
- * this so public visibility remains viewer-only. Use narrowly for local or
62
- * otherwise constrained resources where the resource owner intentionally wants
63
- * unauthenticated link holders to do more than view.
64
- */
65
- publicAccessRole?:
66
- | "viewer"
67
- | "editor"
68
- | "admin"
69
- | ((
70
- resource: any,
71
- ctx: { userEmail?: string; orgId?: string },
72
- ) =>
73
- | "viewer"
74
- | "editor"
75
- | "admin"
76
- | Promise<"viewer" | "editor" | "admin">);
77
- /**
78
- * When `true`, individual user shares (`principalType: "user"`) must target
79
- * an email that is already a member of the same org as the resource, OR has
80
- * a pending invitation to that org. Cross-org user shares are rejected.
81
- *
82
- * Pair with `allowPublic: false` for resources that need a hard "this org
83
- * only" trust boundary. Extensions set this so a malicious caller can't
84
- * widen reach by sharing a code-executing extension to an outsider email.
85
- *
86
- * Default: `false` (matches the historical behavior any email can be granted).
87
- */
88
- requireOrgMemberForUserShares?: boolean;
89
- /**
90
- * Optional per-resource access-context adapter. Most resources should use the
91
- * request user/org unchanged. Templates with an intentional alternate local
92
- * identity can normalize here so the generic framework sharing actions and
93
- * access helpers stay in sync with template-owned actions.
94
- */
95
- resolveAccessContext?: (ctx: { userEmail?: string; orgId?: string }) => {
96
- userEmail?: string;
97
- orgId?: string;
98
- };
99
- /**
100
- * When true, direct ownership is recognized by owner_email regardless of the
101
- * caller's active org. Use this only for resource types where the template's
102
- * own actions already treat owner_email as the cross-org authority and list
103
- * views add their own org filters.
104
- *
105
- * Default: `false`.
106
- */
107
- ownerAccessIgnoresOrg?: boolean;
108
- /**
109
- * Optional external-agent read handoff. When set, the framework-level
110
- * `create-agent-resource-link` action can mint a short-lived, read-only
111
- * `agent_access` URL for this resource. The context endpoint is owned by the
112
- * template so it can expose the same intentionally shareable shape as the
113
- * public page, not a generic raw database row.
114
- */
115
- agentReadable?:
116
- | false
117
- | {
118
- /** Token scope. Include the app name to avoid cross-app collisions. */
119
- resourceKind: string;
120
- /** App-relative JSON endpoint that accepts `id` + `agent_access`. */
121
- getContextPath: (resource: any) => string | undefined;
122
- /** Optional override for the page URL. Defaults to getResourcePath. */
123
- getPagePath?: (resource: any) => string | undefined;
124
- /** Optional override for the default two-hour token lifetime. */
125
- ttlSeconds?: number;
126
- };
127
- }
128
-
129
- // Stash the registry on globalThis so it survives SSR bundle duplication.
130
- // Vite SSR's `noExternal: /^(?!node:)/` policy means @agent-native/core gets
131
- // inlined into every server bundle that imports it and each bundle gets its
132
- // own module-level state. A plain `new Map()` here would create one Map per
133
- // bundle, so the template's `registerShareableResource()` (called from the
134
- // Nitro plugin graph) wouldn't be visible to the framework's auto-mounted
135
- // share-resource action (loaded via `import("../sharing/actions/...js")` in a
136
- // different module instance). Using globalThis collapses them back to one Map.
137
- const REGISTRY_KEY = "__agentNativeShareableResources__";
138
- type RegistryStore = Map<string, ShareableResourceRegistration>;
139
- const globalRegistry: { [K in typeof REGISTRY_KEY]?: RegistryStore } =
140
- globalThis as any;
141
-
142
- function isTestRuntime(): boolean {
143
- return (
144
- process.env.NODE_ENV === "test" ||
145
- process.env.VITEST === "true" ||
146
- process.env.VITEST === "1"
147
- );
148
- }
149
-
150
- function registrationCameFromTestFile(): boolean {
151
- const stack = new Error().stack ?? "";
152
- return /[./\\](?:[^/\\]+[.-])(?:test|spec)\.[cm]?[jt]sx?(?::\d+)?(?::\d+)?/.test(
153
- stack,
154
- );
155
- }
156
-
157
- function getRegistry(): RegistryStore {
158
- let r = globalRegistry[REGISTRY_KEY];
159
- if (!r) {
160
- r = new Map<string, ShareableResourceRegistration>();
161
- globalRegistry[REGISTRY_KEY] = r;
162
- }
163
- return r;
164
- }
165
-
166
- export function registerShareableResource(
167
- entry: ShareableResourceRegistration,
168
- ): void {
169
- if (!isTestRuntime() && registrationCameFromTestFile()) return;
170
- getRegistry().set(entry.type, entry);
171
- }
172
-
173
- export function getShareableResource(
174
- type: string,
175
- ): ShareableResourceRegistration | undefined {
176
- return getRegistry().get(type);
177
- }
178
-
179
- export function requireShareableResource(
180
- type: string,
181
- ): ShareableResourceRegistration {
182
- const reg = getRegistry();
183
- const entry = reg.get(type);
184
- if (!entry) {
185
- throw new Error(
186
- `Unknown shareable resource type: "${type}". Did you forget registerShareableResource()?`,
187
- );
188
- }
189
- return entry;
190
- }
191
-
192
- export function listShareableResources(): ShareableResourceRegistration[] {
193
- return Array.from(getRegistry().values());
194
- }
1
+ /**
2
+ * Registry of shareable resources.
3
+ *
4
+ * Each template registers its ownable resource(s) once on module load so the
5
+ * framework-level share actions (`share-resource`, `list-resource-shares`,
6
+ * etc.) can dispatch to the correct tables.
7
+ *
8
+ * import { registerShareableResource } from "@agent-native/core/sharing";
9
+ * import * as schema from "./schema.js";
10
+ *
11
+ * registerShareableResource({
12
+ * type: "document",
13
+ * resourceTable: schema.documents,
14
+ * sharesTable: schema.documentShares,
15
+ * displayName: "Document",
16
+ * titleColumn: "title",
17
+ * });
18
+ */
19
+
20
+ import { getScopedGlobal } from "../shared/global-scope.js";
21
+
22
+ export interface ShareableResourceRegistration {
23
+ /** Stable identifier used across actions, UI, and analytics. e.g. "document". */
24
+ type: string;
25
+ /** Drizzle table for the parent resource (must have ownableColumns()). */
26
+ resourceTable: any;
27
+ /** Drizzle table produced by createSharesTable(). */
28
+ sharesTable: any;
29
+ /** Human-readable singular label shown in the share dialog. */
30
+ displayName: string;
31
+ /**
32
+ * Column on the resource table that holds a human-readable title for
33
+ * display in the share UI. Default: "title".
34
+ */
35
+ titleColumn?: string;
36
+ /**
37
+ * Optional app-relative path to this resource. Used by share notifications
38
+ * when the caller does not pass a more specific resourceUrl.
39
+ */
40
+ getResourcePath?: (resource: any) => string | undefined;
41
+ /**
42
+ * Drizzle DB accessor from the template's server/db/index.ts. Required —
43
+ * the framework-level share actions and access helpers call this to reach
44
+ * the right DB instance (schema is template-specific).
45
+ */
46
+ getDb: () => any;
47
+ /**
48
+ * When `false`, `visibility: "public"` is rejected by `set-resource-visibility`,
49
+ * and `accessFilter` / `resolveAccess` treat any stored public row as private
50
+ * (defense in depth only owner + explicit shares grant access).
51
+ *
52
+ * Use this for resources that execute code or expose privileged data and must
53
+ * never be reachable by a random authenticated user. Extensions set this:
54
+ * extension HTML runs inside an iframe that calls actions / DB / proxied APIs
55
+ * as the *viewer*, so a public extension would be arbitrary code with the
56
+ * viewer's credentials.
57
+ *
58
+ * Default: `true` (matches the historical behavior — most resources can be public).
59
+ */
60
+ allowPublic?: boolean;
61
+ /**
62
+ * Optional role granted by a public-by-link read. Most resources should omit
63
+ * this so public visibility remains viewer-only. Use narrowly for local or
64
+ * otherwise constrained resources where the resource owner intentionally wants
65
+ * unauthenticated link holders to do more than view.
66
+ */
67
+ publicAccessRole?:
68
+ | "viewer"
69
+ | "editor"
70
+ | "admin"
71
+ | ((
72
+ resource: any,
73
+ ctx: { userEmail?: string; orgId?: string },
74
+ ) =>
75
+ | "viewer"
76
+ | "editor"
77
+ | "admin"
78
+ | Promise<"viewer" | "editor" | "admin">);
79
+ /**
80
+ * When `true`, individual user shares (`principalType: "user"`) must target
81
+ * an email that is already a member of the same org as the resource, OR has
82
+ * a pending invitation to that org. Cross-org user shares are rejected.
83
+ *
84
+ * Pair with `allowPublic: false` for resources that need a hard "this org
85
+ * only" trust boundary. Extensions set this so a malicious caller can't
86
+ * widen reach by sharing a code-executing extension to an outsider email.
87
+ *
88
+ * Default: `false` (matches the historical behavior — any email can be granted).
89
+ */
90
+ requireOrgMemberForUserShares?: boolean;
91
+ /**
92
+ * Optional per-resource access-context adapter. Most resources should use the
93
+ * request user/org unchanged. Templates with an intentional alternate local
94
+ * identity can normalize here so the generic framework sharing actions and
95
+ * access helpers stay in sync with template-owned actions.
96
+ */
97
+ resolveAccessContext?: (ctx: { userEmail?: string; orgId?: string }) => {
98
+ userEmail?: string;
99
+ orgId?: string;
100
+ };
101
+ /**
102
+ * When true, direct ownership is recognized by owner_email regardless of the
103
+ * caller's active org. Use this only for resource types where the template's
104
+ * own actions already treat owner_email as the cross-org authority and list
105
+ * views add their own org filters.
106
+ *
107
+ * Default: `false`.
108
+ */
109
+ ownerAccessIgnoresOrg?: boolean;
110
+ /**
111
+ * Optional external-agent read handoff. When set, the framework-level
112
+ * `create-agent-resource-link` action can mint a short-lived, read-only
113
+ * `agent_access` URL for this resource. The context endpoint is owned by the
114
+ * template so it can expose the same intentionally shareable shape as the
115
+ * public page, not a generic raw database row.
116
+ */
117
+ agentReadable?:
118
+ | false
119
+ | {
120
+ /** Token scope. Include the app name to avoid cross-app collisions. */
121
+ resourceKind: string;
122
+ /** App-relative JSON endpoint that accepts `id` + `agent_access`. */
123
+ getContextPath: (resource: any) => string | undefined;
124
+ /** Optional override for the page URL. Defaults to getResourcePath. */
125
+ getPagePath?: (resource: any) => string | undefined;
126
+ /** Optional override for the default two-hour token lifetime. */
127
+ ttlSeconds?: number;
128
+ };
129
+ }
130
+
131
+ // Stash the registry on globalThis so it survives SSR bundle duplication.
132
+ // Vite SSR's `noExternal: /^(?!node:)/` policy means @agent-native/core gets
133
+ // inlined into every server bundle that imports it and each bundle gets its
134
+ // own module-level state. A plain `new Map()` here would create one Map per
135
+ // bundle, so the template's `registerShareableResource()` (called from the
136
+ // Nitro plugin graph) wouldn't be visible to the framework's auto-mounted
137
+ // share-resource action (loaded via `import("../sharing/actions/...js")` in a
138
+ // different module instance). Using globalThis collapses them back to one Map.
139
+ // Scope-aware + lazily resolved so unified workspace deployments (all apps in
140
+ // one isolate) keep per-app registrations. See shared/global-scope.
141
+ type RegistryStore = Map<string, ShareableResourceRegistration>;
142
+
143
+ function isTestRuntime(): boolean {
144
+ return (
145
+ process.env.NODE_ENV === "test" ||
146
+ process.env.VITEST === "true" ||
147
+ process.env.VITEST === "1"
148
+ );
149
+ }
150
+
151
+ function registrationCameFromTestFile(): boolean {
152
+ const stack = new Error().stack ?? "";
153
+ return /[./\\](?:[^/\\]+[.-])(?:test|spec)\.[cm]?[jt]sx?(?::\d+)?(?::\d+)?/.test(
154
+ stack,
155
+ );
156
+ }
157
+
158
+ function getRegistry(): RegistryStore {
159
+ return getScopedGlobal(
160
+ "agent-native.sharing.shareable-resources",
161
+ () => new Map<string, ShareableResourceRegistration>(),
162
+ );
163
+ }
164
+
165
+ export function registerShareableResource(
166
+ entry: ShareableResourceRegistration,
167
+ ): void {
168
+ if (!isTestRuntime() && registrationCameFromTestFile()) return;
169
+ getRegistry().set(entry.type, entry);
170
+ }
171
+
172
+ export function getShareableResource(
173
+ type: string,
174
+ ): ShareableResourceRegistration | undefined {
175
+ return getRegistry().get(type);
176
+ }
177
+
178
+ export function requireShareableResource(
179
+ type: string,
180
+ ): ShareableResourceRegistration {
181
+ const reg = getRegistry();
182
+ const entry = reg.get(type);
183
+ if (!entry) {
184
+ throw new Error(
185
+ `Unknown shareable resource type: "${type}". Did you forget registerShareableResource()?`,
186
+ );
187
+ }
188
+ return entry;
189
+ }
190
+
191
+ export function listShareableResources(): ShareableResourceRegistration[] {
192
+ return Array.from(getRegistry().values());
193
+ }