@agent-native/core 0.161.23 → 0.163.0
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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +18 -2
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/server/handlers/google-auth.ts +1 -8
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +88 -35
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +36 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -3
- package/corpus/templates/clips/app/lib/camera-composite.ts +15 -1
- package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-crashes-when-a-camera-bubble-starts-at-a-tin.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +30 -40
- package/corpus/templates/clips/desktop/src/components/MicOffConfirmation.tsx +47 -0
- package/corpus/templates/clips/desktop/src/styles.css +110 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +114 -7
- package/corpus/templates/clips/shared/recording-capture.ts +18 -13
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/content/actions/create-content-database.ts +1 -1
- package/corpus/templates/content/actions/create-document.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -5
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +0 -3
- package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +0 -4
- package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +4 -1
- package/corpus/templates/content/app/hooks/use-notion.ts +17 -15
- package/corpus/templates/crm/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +6 -1
- package/corpus/templates/dispatch/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/macros/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +18 -3
- package/corpus/templates/mail/server/handlers/google-auth.ts +1 -8
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +4 -0
- package/corpus/templates/slides/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/actions/_await-fit-check.ts +30 -5
- package/corpus/templates/slides/actions/add-slide.ts +6 -2
- package/corpus/templates/slides/actions/create-deck.ts +2 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +1 -1
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +35 -2
- package/corpus/templates/slides/app/routes/p.$id.tsx +3 -1
- package/corpus/templates/slides/changelog/2026-08-18-generated-slides-preserve-speaker-notes.md +6 -0
- package/corpus/templates/slides/server/handlers/assets.ts +23 -12
- package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +15 -6
- package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +15 -6
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +34 -19
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +1 -0
- package/corpus/templates/slides/server/handlers/share.ts +1 -1
- package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/server/routes/api/deck-agent-context.json.get.ts +1 -1
- package/corpus/templates/slides/server/routes/api/exports/[filename].get.ts +9 -3
- package/corpus/templates/slides/server/routes/api/exports/google-slides.post.ts +12 -5
- package/corpus/templates/slides/server/routes/api/exports/html.post.ts +9 -7
- package/corpus/templates/slides/server/routes/api/exports/pptx.post.ts +9 -7
- package/corpus/templates/slides/shared/api.ts +7 -1
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/agent/engine/translate-anthropic.js +27 -2
- package/dist/agent/production-agent.d.ts +2 -2
- package/dist/agent/production-agent.js +16 -8
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.js +6 -4
- package/dist/agent/tool-approval-store.d.ts +10 -1
- package/dist/agent/tool-approval-store.js +19 -2
- package/dist/agent/types.d.ts +9 -0
- package/dist/app-config/schema.d.ts +1 -0
- package/dist/app-config/workspace.d.ts +1 -0
- package/dist/app-config/workspace.js +8 -0
- package/dist/chat-threads/schema.d.ts +2 -2
- package/dist/client/AssistantChat.js +14 -6
- package/dist/client/EnvironmentBadge.d.ts +15 -0
- package/dist/client/EnvironmentBadge.js +79 -0
- package/dist/client/MultiTabAssistantChat.js +73 -17
- package/dist/client/agent-chat-adapter.js +11 -1
- package/dist/client/api-path.js +14 -1
- package/dist/client/app-providers.js +2 -1
- package/dist/client/chat/tool-call-display.d.ts +12 -2
- package/dist/client/chat/tool-call-display.js +17 -7
- package/dist/client/chat/widgets/WorkspaceFileWidget.js +1 -1
- package/dist/client/chat/widgets/builtin-tool-renderers.d.ts +6 -0
- package/dist/client/chat/widgets/builtin-tool-renderers.js +19 -0
- package/dist/client/onboarding/FirstRunOnboarding.js +46 -32
- package/dist/client/onboarding/use-onboarding.d.ts +8 -1
- package/dist/client/onboarding/use-onboarding.js +22 -7
- package/dist/client/org/TeamPage.js +15 -2
- package/dist/client/org/hooks.d.ts +2 -0
- package/dist/client/org/hooks.js +12 -0
- package/dist/client/org/index.d.ts +2 -2
- package/dist/client/org/index.js +1 -1
- package/dist/client/session-replay.js +58 -15
- package/dist/client/settings/SettingsTabsPage.js +19 -6
- package/dist/client/sharing/ShareButton.js +43 -18
- package/dist/client/sharing/useShareButtonController.d.ts +12 -2
- package/dist/client/sharing/useShareButtonController.js +38 -8
- package/dist/client/sse-event-processor.d.ts +7 -0
- package/dist/client/sse-event-processor.js +4 -1
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/use-action.js +26 -0
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.js +53 -0
- package/dist/dashboard-storage/schema.d.ts +2 -2
- package/dist/data-programs/schema.d.ts +2 -2
- package/dist/extensions/fetch-tool.js +8 -2
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/extensions/store.js +3 -0
- package/dist/localization/core-messages/ar-SA.js +1 -0
- package/dist/localization/core-messages/de-DE.js +1 -0
- package/dist/localization/core-messages/en-US.d.ts +1 -0
- package/dist/localization/core-messages/en-US.js +1 -0
- package/dist/localization/core-messages/es-ES.js +1 -0
- package/dist/localization/core-messages/fr-FR.js +1 -0
- package/dist/localization/core-messages/hi-IN.js +1 -0
- package/dist/localization/core-messages/ja-JP.js +1 -0
- package/dist/localization/core-messages/ko-KR.js +1 -0
- package/dist/localization/core-messages/pt-BR.js +1 -0
- package/dist/localization/core-messages/zh-CN.js +1 -0
- package/dist/localization/core-messages/zh-TW.js +1 -0
- package/dist/localization/core-messages.d.ts +1 -0
- package/dist/localization/default-messages.d.ts +4 -0
- package/dist/localization/default-messages.js +4 -0
- package/dist/mcp/embed-app.js +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/handlers.d.ts +6 -1
- package/dist/org/handlers.js +43 -0
- package/dist/org/index.d.ts +3 -3
- package/dist/org/index.js +2 -2
- package/dist/org/migrations.js +33 -0
- package/dist/org/plugin.js +10 -1
- package/dist/org/schema.d.ts +315 -0
- package/dist/org/schema.js +20 -1
- package/dist/org/types.d.ts +3 -0
- package/dist/org/workspace-app-access.d.ts +10 -0
- package/dist/org/workspace-app-access.js +179 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/index.d.ts +10 -0
- package/dist/provider-api/index.js +45 -9
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +24 -4
- package/dist/server/poll.js +13 -3
- package/dist/server/sentry.d.ts +1 -1
- package/dist/sharing/access.d.ts +2 -2
- package/dist/sharing/access.js +56 -3
- package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
- package/dist/sharing/actions/list-resource-shares.js +26 -1
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/actions/share-resource.js +23 -4
- package/dist/sharing/actions/unshare-resource.d.ts +1 -1
- package/dist/sharing/actions/unshare-resource.js +1 -1
- package/dist/sharing/registry.d.ts +12 -0
- package/dist/sharing/schema.d.ts +4 -4
- package/dist/sharing/schema.js +2 -2
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/vite/client.d.ts +5 -0
- package/dist/vite/client.js +64 -2
- package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +9 -1
- package/dist/workspace-connections/actions/list-workspace-user-groups.js +9 -4
- package/dist/workspace-connections/groups.d.ts +2 -0
- package/dist/workspace-connections/groups.js +16 -5
- package/dist/workspace-files/actions.d.ts +1 -8
- package/dist/workspace-files/actions.js +5 -21
- package/dist/workspace-files/index.d.ts +1 -1
- package/dist/workspace-files/index.js +1 -1
- package/dist/workspace-files/store.d.ts +18 -0
- package/dist/workspace-files/store.js +24 -3
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
package/corpus/README.md
CHANGED
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -1623,8 +1623,15 @@ function MetricRenderer({
|
|
|
1623
1623
|
|
|
1624
1624
|
function numericTableValue(value: unknown): number | null {
|
|
1625
1625
|
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
1626
|
-
if (typeof value !== "string"
|
|
1627
|
-
const
|
|
1626
|
+
if (typeof value !== "string") return null;
|
|
1627
|
+
const trimmed = value.trim();
|
|
1628
|
+
if (trimmed === "") return null;
|
|
1629
|
+
// Strip display formatting (currency symbols, thousands separators,
|
|
1630
|
+
// percent signs, whitespace) so a formatted numeric column ("$1,234",
|
|
1631
|
+
// "12.5%") still parses as a number instead of falling back to text.
|
|
1632
|
+
const cleaned = trimmed.replace(/[$€£¥%,\s]/g, "");
|
|
1633
|
+
if (cleaned === "" || cleaned === "-" || cleaned === "+") return null;
|
|
1634
|
+
const numeric = Number(cleaned);
|
|
1628
1635
|
return Number.isFinite(numeric) ? numeric : null;
|
|
1629
1636
|
}
|
|
1630
1637
|
|
|
@@ -1651,6 +1658,15 @@ export function sortTableRows(
|
|
|
1651
1658
|
|
|
1652
1659
|
const an = numericTableValue(av);
|
|
1653
1660
|
const bn = numericTableValue(bv);
|
|
1661
|
+
|
|
1662
|
+
// A value that fails to parse as a number sorts after one that
|
|
1663
|
+
// does, regardless of column direction — same rule as null above.
|
|
1664
|
+
// Keeps a mostly-numeric column ("10", "9", "N/A") grouped by
|
|
1665
|
+
// magnitude instead of interleaving text lexically with numbers,
|
|
1666
|
+
// and never coerces the unparseable value to 0.
|
|
1667
|
+
if (an !== null && bn === null) return -1;
|
|
1668
|
+
if (an === null && bn !== null) return 1;
|
|
1669
|
+
|
|
1654
1670
|
const comparison =
|
|
1655
1671
|
an !== null && bn !== null
|
|
1656
1672
|
? an - bn
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -163,23 +163,16 @@ function googleOAuthErrorPayload(
|
|
|
163
163
|
message: string;
|
|
164
164
|
code?: string;
|
|
165
165
|
accountId?: string;
|
|
166
|
-
existingOwner?: string;
|
|
167
|
-
attemptedOwner?: string;
|
|
168
166
|
} {
|
|
169
167
|
if (
|
|
170
168
|
error instanceof OAuthAccountOwnedByOtherUserError ||
|
|
171
169
|
error?.name === "OAuthAccountOwnedByOtherUserError"
|
|
172
170
|
) {
|
|
173
171
|
const account = error.accountId || "This Google account";
|
|
174
|
-
const existingOwner = error.existingOwner || undefined;
|
|
175
|
-
const attemptedOwner = error.attemptedOwner || undefined;
|
|
176
|
-
const message = `${account} is connected to another login. Sign out, then sign in with ${account}.`;
|
|
177
172
|
return {
|
|
178
|
-
message,
|
|
173
|
+
message: `${account} is already connected to another login. Sign out, then sign in with the login that originally connected it.`,
|
|
179
174
|
code: "account_owner_mismatch",
|
|
180
175
|
accountId: error.accountId,
|
|
181
|
-
existingOwner,
|
|
182
|
-
attemptedOwner,
|
|
183
176
|
};
|
|
184
177
|
}
|
|
185
178
|
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -2,6 +2,7 @@ import { agentNativePath } from "@agent-native/core/client/api-path";
|
|
|
2
2
|
import { useT } from "@agent-native/core/client/i18n";
|
|
3
3
|
import { isSelectableAudioInputDevice } from "@shared/media-device-selection";
|
|
4
4
|
import {
|
|
5
|
+
IconArrowLeft,
|
|
5
6
|
IconBrowser,
|
|
6
7
|
IconCamera,
|
|
7
8
|
IconChevronDown,
|
|
@@ -14,16 +15,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
|
14
15
|
|
|
15
16
|
import { CaptureInstallInlineLink } from "@/components/capture-install-options";
|
|
16
17
|
import { ImportMenu } from "@/components/import-menu";
|
|
17
|
-
import {
|
|
18
|
-
AlertDialog,
|
|
19
|
-
AlertDialogAction,
|
|
20
|
-
AlertDialogCancel,
|
|
21
|
-
AlertDialogContent,
|
|
22
|
-
AlertDialogDescription,
|
|
23
|
-
AlertDialogFooter,
|
|
24
|
-
AlertDialogHeader,
|
|
25
|
-
AlertDialogTitle,
|
|
26
|
-
} from "@/components/ui/alert-dialog";
|
|
27
18
|
import { Button } from "@/components/ui/button";
|
|
28
19
|
import {
|
|
29
20
|
Collapsible,
|
|
@@ -124,6 +115,69 @@ type SurfaceOption = {
|
|
|
124
115
|
|
|
125
116
|
const REQUEST_MIC_ACCESS_VALUE = "__clips_request_microphone_access__";
|
|
126
117
|
|
|
118
|
+
function MicOffConfirmation({
|
|
119
|
+
onBack,
|
|
120
|
+
onUnmute,
|
|
121
|
+
onContinue,
|
|
122
|
+
}: {
|
|
123
|
+
onBack: () => void;
|
|
124
|
+
onUnmute: () => void;
|
|
125
|
+
onContinue: () => void;
|
|
126
|
+
}) {
|
|
127
|
+
const t = useT();
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div className="fixed inset-0 z-50 flex min-h-screen flex-col overflow-y-auto bg-background text-foreground">
|
|
131
|
+
<header className="flex shrink-0 items-center px-6 py-5 sm:px-10">
|
|
132
|
+
<button
|
|
133
|
+
type="button"
|
|
134
|
+
onClick={onBack}
|
|
135
|
+
className="inline-flex items-center gap-2 rounded-lg px-1 py-1 text-lg font-semibold transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
136
|
+
>
|
|
137
|
+
<IconArrowLeft className="h-5 w-5 rtl:-scale-x-100" />
|
|
138
|
+
{t("recordingPage.back")}
|
|
139
|
+
</button>
|
|
140
|
+
</header>
|
|
141
|
+
|
|
142
|
+
<main className="flex flex-1 flex-col items-center justify-center px-6 py-12 text-center sm:py-16">
|
|
143
|
+
<div
|
|
144
|
+
className="relative flex h-28 w-28 items-center justify-center rounded-full bg-destructive/10 text-destructive"
|
|
145
|
+
aria-hidden="true"
|
|
146
|
+
>
|
|
147
|
+
<IconMicrophone className="h-12 w-12" strokeWidth={1.75} />
|
|
148
|
+
<span className="absolute h-1 w-20 rotate-45 rounded-full bg-destructive" />
|
|
149
|
+
</div>
|
|
150
|
+
<h1 className="mt-10 text-3xl font-semibold tracking-tight sm:text-4xl">
|
|
151
|
+
{t("preRecord.micOffConfirmTitle")}
|
|
152
|
+
</h1>
|
|
153
|
+
<p className="mt-4 max-w-md text-base leading-7 text-muted-foreground sm:text-lg">
|
|
154
|
+
{t("preRecord.micOffConfirmDescription")}
|
|
155
|
+
</p>
|
|
156
|
+
</main>
|
|
157
|
+
|
|
158
|
+
<footer className="flex shrink-0 justify-center border-t border-border bg-muted/20 px-6 py-6 sm:px-10">
|
|
159
|
+
<div className="flex w-full max-w-md gap-4">
|
|
160
|
+
<Button
|
|
161
|
+
type="button"
|
|
162
|
+
variant="outline"
|
|
163
|
+
onClick={onUnmute}
|
|
164
|
+
className="h-12 flex-1 rounded-xl text-base font-semibold"
|
|
165
|
+
>
|
|
166
|
+
{t("preRecord.unmuteMicrophone")}
|
|
167
|
+
</Button>
|
|
168
|
+
<Button
|
|
169
|
+
type="button"
|
|
170
|
+
onClick={onContinue}
|
|
171
|
+
className="h-12 flex-1 rounded-xl text-base font-semibold"
|
|
172
|
+
>
|
|
173
|
+
{t("preRecord.startWithoutMic")}
|
|
174
|
+
</Button>
|
|
175
|
+
</div>
|
|
176
|
+
</footer>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
127
181
|
function isPseudoMediaDeviceId(value: string | null | undefined): boolean {
|
|
128
182
|
const id = value?.trim().toLowerCase();
|
|
129
183
|
return !id || id === "default" || id === "communications";
|
|
@@ -465,6 +519,20 @@ export function PreRecordPanel({
|
|
|
465
519
|
onStart(buildStartOpts());
|
|
466
520
|
}, [micId, buildStartOpts, onStart]);
|
|
467
521
|
|
|
522
|
+
const handleMicWarningBack = useCallback(() => {
|
|
523
|
+
setMicWarningOpen(false);
|
|
524
|
+
}, []);
|
|
525
|
+
|
|
526
|
+
const handleMicWarningUnmute = useCallback(() => {
|
|
527
|
+
chooseMic("default");
|
|
528
|
+
setMicWarningOpen(false);
|
|
529
|
+
}, [chooseMic]);
|
|
530
|
+
|
|
531
|
+
const handleMicWarningContinue = useCallback(() => {
|
|
532
|
+
setMicWarningOpen(false);
|
|
533
|
+
onStart(buildStartOpts());
|
|
534
|
+
}, [buildStartOpts, onStart]);
|
|
535
|
+
|
|
468
536
|
const selectedCameraLabel = useMemo(() => {
|
|
469
537
|
if (!needsCamera) return null;
|
|
470
538
|
if (cameraId === "default") return t("preRecord.defaultCamera");
|
|
@@ -619,6 +687,16 @@ export function PreRecordPanel({
|
|
|
619
687
|
return null;
|
|
620
688
|
}, [audioEnabled, cameraTest.status, micTest.status, needsCamera, t]);
|
|
621
689
|
|
|
690
|
+
if (micWarningOpen) {
|
|
691
|
+
return (
|
|
692
|
+
<MicOffConfirmation
|
|
693
|
+
onBack={handleMicWarningBack}
|
|
694
|
+
onUnmute={handleMicWarningUnmute}
|
|
695
|
+
onContinue={handleMicWarningContinue}
|
|
696
|
+
/>
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
622
700
|
return (
|
|
623
701
|
<div className="mx-auto w-full max-w-lg overflow-hidden rounded-2xl border border-border bg-card shadow-lg">
|
|
624
702
|
<div className="p-6">
|
|
@@ -965,31 +1043,6 @@ export function PreRecordPanel({
|
|
|
965
1043
|
</>
|
|
966
1044
|
)}
|
|
967
1045
|
</div>
|
|
968
|
-
|
|
969
|
-
<AlertDialog open={micWarningOpen} onOpenChange={setMicWarningOpen}>
|
|
970
|
-
<AlertDialogContent>
|
|
971
|
-
<AlertDialogHeader>
|
|
972
|
-
<AlertDialogTitle>
|
|
973
|
-
{t("preRecord.micOffConfirmTitle")}
|
|
974
|
-
</AlertDialogTitle>
|
|
975
|
-
<AlertDialogDescription>
|
|
976
|
-
{t("preRecord.micOffConfirmDescription")}
|
|
977
|
-
</AlertDialogDescription>
|
|
978
|
-
</AlertDialogHeader>
|
|
979
|
-
<AlertDialogFooter>
|
|
980
|
-
<AlertDialogCancel>{t("common.cancel")}</AlertDialogCancel>
|
|
981
|
-
<AlertDialogAction
|
|
982
|
-
onClick={(event) => {
|
|
983
|
-
event.preventDefault();
|
|
984
|
-
setMicWarningOpen(false);
|
|
985
|
-
onStart(buildStartOpts());
|
|
986
|
-
}}
|
|
987
|
-
>
|
|
988
|
-
{t("preRecord.startWithoutMic")}
|
|
989
|
-
</AlertDialogAction>
|
|
990
|
-
</AlertDialogFooter>
|
|
991
|
-
</AlertDialogContent>
|
|
992
|
-
</AlertDialog>
|
|
993
1046
|
</div>
|
|
994
1047
|
);
|
|
995
1048
|
}
|