@agent-native/core 0.164.4 → 0.164.12
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/calendar/.agents/skills/event-management/SKILL.md +84 -0
- package/corpus/templates/calendar/AGENTS.md +5 -0
- package/corpus/templates/calendar/actions/delete-event.ts +1 -1
- package/corpus/templates/calendar/actions/delete-events.ts +508 -0
- package/corpus/templates/calendar/actions/event-action-helpers.ts +1 -1
- package/corpus/templates/calendar/actions/list-events.ts +53 -0
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +36 -47
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +3 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +18 -1
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +256 -38
- package/corpus/templates/calendar/app/hooks/use-google-auth.ts +43 -3
- package/corpus/templates/calendar/app/i18n-data.ts +120 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +113 -0
- package/corpus/templates/calendar/changelog/2026-08-18-the-agent-can-now-remove-many-meetings-at-once-such-as-every.md +6 -0
- package/corpus/templates/calendar/server/handlers/google-auth.ts +119 -3
- package/corpus/templates/calendar/server/lib/event-weekday.ts +112 -0
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +12 -0
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +18 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +114 -20
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +83 -78
- package/corpus/templates/clips/changelog/2026-08-19-clips-nightly-builds-are-available-for-trying-the-latest-upd.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-19-social-preview-video-frames.md +1 -0
- package/corpus/templates/clips/desktop/README.md +19 -4
- package/corpus/templates/clips/desktop/src/app.tsx +78 -16
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -2
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -0
- package/corpus/templates/clips/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +41 -3
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +22 -1
- package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +41 -22
- package/corpus/templates/factory/AGENTS.md +3 -2
- package/corpus/templates/factory/actions/get-factory-graph-version.ts +69 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +4 -0
- package/corpus/templates/factory/actions/list-factory-graph-versions.ts +82 -0
- package/corpus/templates/factory/actions/restore-factory-graph-version.ts +163 -0
- package/corpus/templates/factory/actions/save-factory-graph.ts +93 -60
- package/corpus/templates/factory/actions/start-builder-for-item.ts +19 -17
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +100 -36
- package/corpus/templates/factory/app/components/factory/FactoryHistoryView.tsx +709 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +62 -2
- package/corpus/templates/factory/app/components/ui/alert-dialog.tsx +1 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +47 -0
- package/corpus/templates/factory/app/routes/factory.tsx +324 -61
- package/corpus/templates/factory/server/connectors/slack.ts +44 -2
- package/corpus/templates/factory/server/plugins/agent-chat.ts +12 -8
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +13 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +5 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +72 -4
- package/corpus/templates/mail/actions/view-screen.ts +1 -1
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -18
- package/corpus/templates/mail/server/handlers/google-auth.ts +125 -24
- package/corpus/templates/mail/server/lib/gmail-query.ts +5 -2
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +0 -12
- package/corpus/templates/plan/changelog/2026-08-19-plan-prompts-now-guide-you-to-connect-ai-before-sending-and-.md +6 -0
- package/corpus/templates/slides/actions/approve-deck-access-request.ts +234 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +35 -2
- package/corpus/templates/slides/actions/request-deck-access.ts +263 -64
- package/corpus/templates/slides/app/components/editor/MissingDeckAccessPane.tsx +196 -0
- package/corpus/templates/slides/app/components/editor/RequestDeckAccessDialog.tsx +101 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +7 -4
- package/corpus/templates/slides/app/i18n/en-US.ts +29 -6
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +147 -169
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +250 -0
- package/corpus/templates/slides/server/db/schema.ts +8 -0
- package/corpus/templates/slides/server/lib/access-request-email.ts +36 -0
- package/corpus/templates/slides/server/lib/emails.ts +26 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +7 -0
- package/corpus/templates/slides/server/plugins/db.ts +50 -0
- package/corpus/templates/slides/shared/deck-access.ts +31 -0
- package/dist/a2a/task-store.d.ts +1 -0
- package/dist/a2a/task-store.js +1 -1
- package/dist/agent/observational-memory/store.d.ts +1 -0
- package/dist/agent/observational-memory/store.js +1 -1
- package/dist/agent/run-store.d.ts +1 -0
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/tool-approval-store.d.ts +1 -0
- package/dist/agent/tool-approval-store.js +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.js +1 -1
- package/dist/browser-sessions/store.d.ts +1 -0
- package/dist/browser-sessions/store.js +1 -1
- package/dist/checkpoints/store.d.ts +1 -0
- package/dist/checkpoints/store.js +1 -1
- package/dist/cli/code-agent-schedules.d.ts +11 -0
- package/dist/cli/code-agent-schedules.js +44 -5
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AssistantChat.d.ts +5 -1
- package/dist/client/AssistantChat.js +40 -6
- package/dist/client/EnvironmentBadge.d.ts +7 -13
- package/dist/client/EnvironmentBadge.js +43 -92
- package/dist/client/agent-chat/index.d.ts +1 -0
- package/dist/client/agent-chat/index.js +1 -0
- package/dist/client/agent-chat-adapter.js +76 -50
- package/dist/client/app-providers.js +4 -4
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.js +28 -1
- package/dist/client/chat/run-recovery.js +26 -0
- package/dist/client/chat-first/apps-rail.d.ts +1 -0
- package/dist/client/chat-first/apps-rail.js +28 -2
- package/dist/client/sse-event-processor.js +13 -8
- package/dist/client/use-active-agent-chat-run.d.ts +2 -0
- package/dist/client/use-active-agent-chat-run.js +22 -0
- package/dist/coding-tools/sandbox/executions-store.d.ts +1 -0
- package/dist/coding-tools/sandbox/executions-store.js +1 -1
- package/dist/collab/awareness-store.d.ts +1 -0
- package/dist/collab/awareness-store.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +1 -0
- package/dist/collab/storage.js +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.js +3 -3
- package/dist/db/ddl-guard.js +8 -0
- package/dist/db/migration-runtime.d.ts +23 -0
- package/dist/db/migration-runtime.js +41 -0
- package/dist/db/migrations.d.ts +1 -2
- package/dist/db/migrations.js +2 -24
- package/dist/email-catalog/log.d.ts +1 -0
- package/dist/email-catalog/log.js +1 -1
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.js +1 -0
- package/dist/guards/release-schema-complete.d.ts +22 -0
- package/dist/guards/release-schema-complete.js +144 -0
- package/dist/integrations/a2a-continuations-store.d.ts +1 -0
- package/dist/integrations/a2a-continuations-store.js +1 -1
- package/dist/integrations/awaiting-input-store.d.ts +1 -0
- package/dist/integrations/awaiting-input-store.js +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.js +1 -1
- package/dist/integrations/controls-store.d.ts +1 -0
- package/dist/integrations/controls-store.js +1 -1
- package/dist/integrations/identity-links-store.d.ts +1 -0
- package/dist/integrations/identity-links-store.js +1 -1
- package/dist/integrations/installations-store.d.ts +1 -0
- package/dist/integrations/installations-store.js +1 -1
- package/dist/integrations/remote-commands-store.d.ts +1 -0
- package/dist/integrations/remote-commands-store.js +1 -1
- package/dist/integrations/remote-devices-store.d.ts +1 -0
- package/dist/integrations/remote-devices-store.js +1 -1
- package/dist/integrations/remote-push-store.d.ts +1 -0
- package/dist/integrations/remote-push-store.js +1 -1
- package/dist/integrations/remote-run-events-store.d.ts +1 -0
- package/dist/integrations/remote-run-events-store.js +1 -1
- package/dist/integrations/scope-store.d.ts +1 -0
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/thread-mapping-store.d.ts +1 -0
- package/dist/integrations/thread-mapping-store.js +1 -1
- package/dist/integrations/usage-budget-store.d.ts +1 -0
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/jobs/background-automation-runner.js +111 -9
- package/dist/jobs/run-history.d.ts +1 -0
- package/dist/jobs/run-history.js +1 -1
- package/dist/jobs/scheduler-health.d.ts +1 -0
- package/dist/jobs/scheduler-health.js +1 -1
- package/dist/mcp/approval-store.d.ts +1 -0
- package/dist/mcp/approval-store.js +1 -1
- package/dist/mcp/connect-store.d.ts +1 -0
- package/dist/mcp/connect-store.js +1 -1
- package/dist/mcp/oauth-store.d.ts +1 -0
- package/dist/mcp/oauth-store.js +1 -1
- package/dist/notifications/store.d.ts +1 -0
- package/dist/notifications/store.js +1 -1
- package/dist/oauth-tokens/store.d.ts +1 -0
- package/dist/oauth-tokens/store.js +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/progress/store.d.ts +1 -0
- package/dist/progress/store.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/provider-api/corpus-jobs-store.d.ts +1 -0
- package/dist/provider-api/corpus-jobs-store.js +1 -1
- package/dist/provider-api/custom-registry.d.ts +1 -0
- package/dist/provider-api/custom-registry.js +1 -1
- package/dist/provider-api/quota-governor.d.ts +1 -0
- package/dist/provider-api/quota-governor.js +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts +1 -0
- package/dist/provider-api/staged-datasets-store.js +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/resources/store.d.ts +1 -0
- package/dist/resources/store.js +1 -1
- package/dist/scripts/dev/index.js +15 -1
- package/dist/search/index.js +3 -0
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/secrets/storage.d.ts +1 -0
- package/dist/secrets/storage.js +1 -1
- package/dist/server/agent-chat-plugin.js +38 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-teams-run-queue.d.ts +1 -0
- package/dist/server/agent-teams-run-queue.js +1 -1
- package/dist/server/auth-marketing.js +3 -1
- package/dist/server/auth.d.ts +18 -1
- package/dist/server/auth.js +370 -154
- package/dist/server/embed-session.d.ts +1 -0
- package/dist/server/embed-session.js +1 -1
- package/dist/server/google-auth-plugin.js +3 -1
- package/dist/server/google-oauth.d.ts +10 -0
- package/dist/server/google-oauth.js +25 -1
- package/dist/server/identity-sso-store.d.ts +1 -0
- package/dist/server/identity-sso-store.js +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/onboarding-html.js +200 -31
- package/dist/server/poll.d.ts +2 -0
- package/dist/server/poll.js +19 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +5 -0
- package/dist/server/release-schema.d.ts +46 -0
- package/dist/server/release-schema.js +307 -0
- package/dist/settings/store.d.ts +1 -0
- package/dist/settings/store.js +1 -1
- package/dist/shared/environment-lanes.d.ts +28 -0
- package/dist/shared/environment-lanes.js +61 -0
- package/dist/sharing/actions/share-resource.js +22 -2
- package/dist/styles/agent-native.css +17 -15
- package/dist/triggers/routes.d.ts +11 -0
- package/dist/triggers/routes.js +10 -0
- package/dist/usage/alerts-store.d.ts +1 -0
- package/dist/usage/alerts-store.js +1 -1
- package/dist/usage/store.d.ts +1 -0
- package/dist/usage/store.js +1 -1
- package/docs/content/actions-access-control.mdx +136 -2
- package/docs/content/actions-agent-tools.mdx +101 -0
- package/docs/content/actions-defining.mdx +2 -2
- package/docs/content/audit-log.mdx +1 -1
- package/docs/content/authentication.mdx +1 -1
- package/docs/content/cloudflare.mdx +43 -0
- package/docs/content/creating-templates.mdx +1 -1
- package/docs/content/deploy-an-app.mdx +109 -0
- package/docs/content/deployment-environment-variables.mdx +101 -0
- package/docs/content/deployment.mdx +125 -792
- package/docs/content/docs-components.mdx +2 -2
- package/docs/content/environment-variables.mdx +41 -41
- package/docs/content/file-uploads.mdx +74 -40
- package/docs/content/harness-agents.mdx +2 -2
- package/docs/content/internationalization.mdx +61 -65
- package/docs/content/key-concepts.mdx +3 -3
- package/docs/content/multi-app-workspace.mdx +2 -2
- package/docs/content/netlify.mdx +47 -0
- package/docs/content/node-docker.mdx +138 -0
- package/docs/content/organizations-teams-permissions.mdx +5 -5
- package/docs/content/other-platforms.mdx +27 -0
- package/docs/content/ssr-caching.mdx +45 -0
- package/docs/content/template-assets-developers.mdx +2 -2
- package/docs/content/template-chat-developers.mdx +2 -2
- package/docs/content/template-content-developers.mdx +2 -2
- package/docs/content/{local-file-mode.mdx → template-content-local-files.mdx} +2 -1
- package/docs/content/template-content-sync.mdx +2 -2
- package/docs/content/toolkit-agent-ux.mdx +1 -1
- package/docs/content/toolkit-resources.mdx +2 -2
- package/docs/content/updating-ui-in-production.mdx +35 -0
- package/docs/content/vercel.mdx +38 -0
- package/docs/content/what-is-agent-native.mdx +1 -1
- package/docs/content/workspace-deployment.mdx +350 -0
- package/package.json +2 -2
- package/docs/content/agents.mdx +0 -9
- package/docs/content/database.mdx +0 -317
- package/docs/content/human-approval.mdx +0 -156
|
@@ -2062,11 +2062,19 @@ export function App() {
|
|
|
2062
2062
|
const controller = new AbortController();
|
|
2063
2063
|
const abortTimer = setTimeout(() => controller.abort(), POLL_ABORT_MS);
|
|
2064
2064
|
try {
|
|
2065
|
-
const exchangeParams = new URLSearchParams({ flow_id: flowId });
|
|
2066
|
-
if (verifier) exchangeParams.set("verifier", verifier);
|
|
2067
2065
|
const xr = await fetch(
|
|
2068
|
-
`${base}/_agent-native/auth/desktop-exchange
|
|
2069
|
-
{
|
|
2066
|
+
`${base}/_agent-native/auth/desktop-exchange?flow_id=${encodeURIComponent(flowId)}`,
|
|
2067
|
+
{
|
|
2068
|
+
credentials: "include",
|
|
2069
|
+
...(verifier
|
|
2070
|
+
? {
|
|
2071
|
+
headers: {
|
|
2072
|
+
"X-Agent-Native-Desktop-Verifier": verifier,
|
|
2073
|
+
},
|
|
2074
|
+
}
|
|
2075
|
+
: {}),
|
|
2076
|
+
signal: controller.signal,
|
|
2077
|
+
},
|
|
2070
2078
|
);
|
|
2071
2079
|
if (!xr.ok) {
|
|
2072
2080
|
if (Date.now() - start > TIMEOUT_MS) {
|
|
@@ -2130,25 +2138,79 @@ export function App() {
|
|
|
2130
2138
|
void tick();
|
|
2131
2139
|
}
|
|
2132
2140
|
|
|
2133
|
-
// Google
|
|
2134
|
-
// the
|
|
2135
|
-
//
|
|
2141
|
+
// Google verification stays in the bound Tauri WebView so the callback sees
|
|
2142
|
+
// the same browser-binding cookie. Magic-link verification still completes
|
|
2143
|
+
// in the system browser through its own exchange flow.
|
|
2136
2144
|
async function signInExternal() {
|
|
2137
2145
|
if (signInInflightRef.current) return;
|
|
2138
2146
|
signInInflightRef.current = true;
|
|
2139
2147
|
|
|
2140
2148
|
try {
|
|
2141
2149
|
setSignInError(null);
|
|
2142
|
-
const flowId =
|
|
2143
|
-
|
|
2144
|
-
|
|
2150
|
+
const flowId = crypto.randomUUID?.() ?? null;
|
|
2151
|
+
const verifier = (() => {
|
|
2152
|
+
const randomUuid = crypto.randomUUID;
|
|
2153
|
+
if (typeof randomUuid === "function") {
|
|
2154
|
+
return `${randomUuid.call(crypto)}${randomUuid.call(crypto)}`;
|
|
2155
|
+
}
|
|
2156
|
+
if (typeof crypto.getRandomValues === "function") {
|
|
2157
|
+
const bytes = new Uint8Array(32);
|
|
2158
|
+
crypto.getRandomValues(bytes);
|
|
2159
|
+
let binary = "";
|
|
2160
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
2161
|
+
return btoa(binary)
|
|
2162
|
+
.replace(/\+/g, "-")
|
|
2163
|
+
.replace(/\//g, "_")
|
|
2164
|
+
.replace(/=+$/, "");
|
|
2165
|
+
}
|
|
2166
|
+
return null;
|
|
2167
|
+
})();
|
|
2168
|
+
if (!flowId || !verifier) {
|
|
2169
|
+
// A Math.random flow id is guessable, which lets anyone else claim this
|
|
2170
|
+
// sign-in's exchange slot; fail closed rather than weaken the credential.
|
|
2171
|
+
throw new Error("Secure OAuth flow generation is unavailable.");
|
|
2172
|
+
}
|
|
2145
2173
|
const base = serverUrl.replace(/\/+$/, "");
|
|
2146
2174
|
|
|
2147
|
-
|
|
2148
|
-
|
|
2175
|
+
const authParams = new URLSearchParams({
|
|
2176
|
+
desktop: "1",
|
|
2177
|
+
flow_id: flowId,
|
|
2178
|
+
webview: "1",
|
|
2179
|
+
});
|
|
2180
|
+
const authResponse = await fetch(
|
|
2181
|
+
`${base}/_agent-native/google/auth-url?${authParams.toString()}`,
|
|
2182
|
+
{
|
|
2183
|
+
method: "POST",
|
|
2184
|
+
headers: {
|
|
2185
|
+
Accept: "application/json",
|
|
2186
|
+
"X-Agent-Native-Desktop-Verifier": verifier,
|
|
2187
|
+
},
|
|
2188
|
+
},
|
|
2149
2189
|
);
|
|
2190
|
+
let authPayload: {
|
|
2191
|
+
url?: unknown;
|
|
2192
|
+
error?: unknown;
|
|
2193
|
+
message?: unknown;
|
|
2194
|
+
};
|
|
2195
|
+
try {
|
|
2196
|
+
authPayload = (await authResponse.json()) as typeof authPayload;
|
|
2197
|
+
} catch {
|
|
2198
|
+
throw new Error("Could not start Google sign-in.");
|
|
2199
|
+
}
|
|
2200
|
+
if (!authResponse.ok || typeof authPayload?.url !== "string") {
|
|
2201
|
+
const message =
|
|
2202
|
+
typeof authPayload.message === "string"
|
|
2203
|
+
? authPayload.message
|
|
2204
|
+
: typeof authPayload.error === "string"
|
|
2205
|
+
? authPayload.error
|
|
2206
|
+
: "Could not start Google sign-in.";
|
|
2207
|
+
throw new Error(message);
|
|
2208
|
+
}
|
|
2150
2209
|
setSignInPending("google");
|
|
2151
|
-
|
|
2210
|
+
// Stay in this exact WebView: the auth bootstrap set the HttpOnly
|
|
2211
|
+
// browser-binding cookie here, and the callback returns this page with
|
|
2212
|
+
// the staged session cookie after Google completes.
|
|
2213
|
+
window.location.href = authPayload.url;
|
|
2152
2214
|
} catch (err) {
|
|
2153
2215
|
console.error("[clips-tray] signInExternal failed:", err);
|
|
2154
2216
|
signInInflightRef.current = false;
|
|
@@ -3912,8 +3974,8 @@ export function App() {
|
|
|
3912
3974
|
// (not a separate Tauri window). This avoids Tauri 2's separate-WebKit-
|
|
3913
3975
|
// data-store-per-WebviewWindow cookie-jar issue — the cookie is set in
|
|
3914
3976
|
// the same webview that reads it on the next /auth/session poll.
|
|
3915
|
-
// Google
|
|
3916
|
-
// password
|
|
3977
|
+
// Google verification uses the bound WebView, while magic-link verification
|
|
3978
|
+
// uses the system browser and password stays inline here.
|
|
3917
3979
|
if (authStatus === "anon") {
|
|
3918
3980
|
return (
|
|
3919
3981
|
<div className="app" ref={appRef}>
|
|
@@ -4822,7 +4884,7 @@ function SignInForm({
|
|
|
4822
4884
|
type="button"
|
|
4823
4885
|
className="signin-google"
|
|
4824
4886
|
onClick={onUseBrowser}
|
|
4825
|
-
title="
|
|
4887
|
+
title="Returns to Clips to complete Google sign-in"
|
|
4826
4888
|
>
|
|
4827
4889
|
<GoogleIcon />
|
|
4828
4890
|
Sign in with Google
|
|
@@ -15,8 +15,9 @@ crate-type = ["lib", "cdylib", "staticlib"]
|
|
|
15
15
|
|
|
16
16
|
# Force the dev binary name so macOS shows "Clips" in the Dock / app switcher
|
|
17
17
|
# (macOS derives the display name from the executable filename when the app
|
|
18
|
-
# is unbundled — e.g. during `tauri dev`).
|
|
19
|
-
#
|
|
18
|
+
# is unbundled — e.g. during `tauri dev`). The Nightly release workflow
|
|
19
|
+
# rewrites this target and tauri.conf.json's mainBinaryName to
|
|
20
|
+
# `Clips-Nightly` before packaging so both lanes can coexist.
|
|
20
21
|
[[bin]]
|
|
21
22
|
name = "Clips"
|
|
22
23
|
path = "src/main.rs"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../_agent-native/google/auth-url.get.js";
|
|
@@ -4,10 +4,14 @@ import {
|
|
|
4
4
|
isElectron,
|
|
5
5
|
resolveGoogleSignInCredentials,
|
|
6
6
|
resolveOAuthRedirectUri,
|
|
7
|
+
registerDesktopExchange,
|
|
8
|
+
prepareDesktopOAuthBrowserBinding,
|
|
7
9
|
safeReturnPath,
|
|
8
10
|
} from "@agent-native/core/server";
|
|
9
11
|
import {
|
|
10
12
|
defineEventHandler,
|
|
13
|
+
getHeader,
|
|
14
|
+
getMethod,
|
|
11
15
|
getQuery,
|
|
12
16
|
setResponseStatus,
|
|
13
17
|
type H3Event,
|
|
@@ -54,11 +58,39 @@ export default defineEventHandler(async (event: H3Event) => {
|
|
|
54
58
|
isElectron(event) || q.desktop === "1" || q.desktop === "true";
|
|
55
59
|
const flowId =
|
|
56
60
|
desktop && typeof q.flow_id === "string" ? q.flow_id : undefined;
|
|
61
|
+
if (getMethod(event) === "POST" && (!desktop || !flowId)) {
|
|
62
|
+
setResponseStatus(event, 400);
|
|
63
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
64
|
+
}
|
|
65
|
+
const calendarConnect =
|
|
66
|
+
q.calendar === "1" || q.calendar === "true" || q.product === "calendar";
|
|
67
|
+
let desktopVerifierHash: string | undefined;
|
|
68
|
+
let desktopBrowserBindingHash: string | undefined;
|
|
69
|
+
if (flowId && !calendarConnect) {
|
|
70
|
+
if (getMethod(event) !== "POST" || q.redirect !== undefined) {
|
|
71
|
+
setResponseStatus(event, 400);
|
|
72
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
73
|
+
}
|
|
74
|
+
const verifier = getHeader(event, "x-agent-native-desktop-verifier");
|
|
75
|
+
if (!verifier || q.verifier !== undefined) {
|
|
76
|
+
setResponseStatus(event, 400);
|
|
77
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
desktopBrowserBindingHash = prepareDesktopOAuthBrowserBinding(event);
|
|
81
|
+
desktopVerifierHash = await registerDesktopExchange(
|
|
82
|
+
flowId,
|
|
83
|
+
verifier,
|
|
84
|
+
desktopBrowserBindingHash,
|
|
85
|
+
);
|
|
86
|
+
} catch {
|
|
87
|
+
setResponseStatus(event, 400);
|
|
88
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
57
91
|
const requestedReturn =
|
|
58
92
|
typeof q.return === "string" ? safeReturnPath(q.return) : "/";
|
|
59
93
|
const returnUrl = requestedReturn !== "/" ? requestedReturn : undefined;
|
|
60
|
-
const calendarConnect =
|
|
61
|
-
q.calendar === "1" || q.calendar === "true" || q.product === "calendar";
|
|
62
94
|
const credentials = calendarConnect
|
|
63
95
|
? ((await resolveGoogleOAuthCredentialCandidates())[0] ?? null)
|
|
64
96
|
: resolveGoogleSignInCredentials();
|
|
@@ -84,10 +116,16 @@ export default defineEventHandler(async (event: H3Event) => {
|
|
|
84
116
|
redirectUri,
|
|
85
117
|
owner,
|
|
86
118
|
desktop,
|
|
119
|
+
desktopWebview: desktop && q.webview === "1" && !calendarConnect,
|
|
87
120
|
addAccount: calendarConnect,
|
|
88
121
|
app: CLIPS_GOOGLE_OAUTH_APP_ID,
|
|
89
|
-
returnUrl
|
|
122
|
+
returnUrl:
|
|
123
|
+
desktop && q.webview === "1" && !calendarConnect
|
|
124
|
+
? "/?desktop_auth=complete"
|
|
125
|
+
: returnUrl,
|
|
90
126
|
flowId: calendarConnect ? undefined : flowId,
|
|
127
|
+
desktopVerifierHash,
|
|
128
|
+
desktopBrowserBindingHash,
|
|
91
129
|
});
|
|
92
130
|
|
|
93
131
|
const params = new URLSearchParams({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./auth-url.get.js";
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
oauthErrorPage,
|
|
7
7
|
resolveGoogleSignInCredentials,
|
|
8
8
|
resolveOAuthOwner,
|
|
9
|
+
matchesDesktopOAuthBrowserBinding,
|
|
9
10
|
setDesktopExchange,
|
|
10
11
|
type OAuthStatePayload,
|
|
11
12
|
} from "@agent-native/core/server";
|
|
@@ -31,6 +32,17 @@ async function handleGoogleSignInCallback(
|
|
|
31
32
|
) {
|
|
32
33
|
const desktop = state.desktop;
|
|
33
34
|
const flowId = state.flowId;
|
|
35
|
+
if (
|
|
36
|
+
flowId &&
|
|
37
|
+
(!state.desktopVerifierHash ||
|
|
38
|
+
!state.desktopBrowserBindingHash ||
|
|
39
|
+
!matchesDesktopOAuthBrowserBinding(
|
|
40
|
+
event,
|
|
41
|
+
state.desktopBrowserBindingHash,
|
|
42
|
+
))
|
|
43
|
+
) {
|
|
44
|
+
return oauthErrorPage("Desktop OAuth browser binding is invalid.");
|
|
45
|
+
}
|
|
34
46
|
|
|
35
47
|
try {
|
|
36
48
|
const query = getQuery(event);
|
|
@@ -107,12 +119,21 @@ async function handleGoogleSignInCallback(
|
|
|
107
119
|
});
|
|
108
120
|
|
|
109
121
|
if (flowId && sessionToken) {
|
|
110
|
-
|
|
122
|
+
if (!state.desktopVerifierHash) {
|
|
123
|
+
throw new Error("Missing desktop exchange challenge.");
|
|
124
|
+
}
|
|
125
|
+
await setDesktopExchange(
|
|
126
|
+
flowId,
|
|
127
|
+
sessionToken,
|
|
128
|
+
email,
|
|
129
|
+
state.desktopVerifierHash,
|
|
130
|
+
);
|
|
111
131
|
}
|
|
112
132
|
|
|
113
133
|
return oauthCallbackResponse(event, email, {
|
|
114
134
|
sessionToken,
|
|
115
135
|
desktop,
|
|
136
|
+
desktopWebview: state.desktopWebview,
|
|
116
137
|
returnUrl: state.returnUrl,
|
|
117
138
|
flowId,
|
|
118
139
|
appName: "Clips",
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { defineEventHandler, setResponseHeaders } from "h3";
|
|
1
|
+
import { defineEventHandler, getQuery, setResponseHeaders } from "h3";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Tauri updater manifest endpoint for the Clips desktop app.
|
|
5
5
|
*
|
|
6
6
|
* The installed app only needs this endpoint to be valid JSON when no signed
|
|
7
|
-
* updater bundle is available. If the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* updater bundle is available. If the channel's GitHub pointer release exists,
|
|
8
|
+
* we proxy its signed manifest. If it does not, return a deliberately old
|
|
9
|
+
* no-update manifest so the desktop UI stays quiet instead of surfacing a
|
|
10
10
|
* release-channel setup error to end users.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
type ClipsUpdateChannel = "production" | "nightly";
|
|
14
|
+
|
|
15
|
+
const GITHUB_MANIFEST_URL: Record<ClipsUpdateChannel, string> = {
|
|
16
|
+
production:
|
|
17
|
+
"https://github.com/BuilderIO/agent-native/releases/download/clips-latest/clips-latest.json",
|
|
18
|
+
nightly:
|
|
19
|
+
"https://github.com/BuilderIO/agent-native/releases/download/clips-nightly-latest/clips-nightly-latest.json",
|
|
20
|
+
};
|
|
15
21
|
const CACHE_TTL_MS = 5 * 60_000;
|
|
16
22
|
|
|
17
23
|
// Tauri throws a red-banner error if the requesting client's target triple is
|
|
@@ -48,8 +54,8 @@ export const INERT_MANIFEST = {
|
|
|
48
54
|
},
|
|
49
55
|
};
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
const cache = new Map<ClipsUpdateChannel, { data: unknown; ts: number }>();
|
|
58
|
+
const inFlight = new Map<ClipsUpdateChannel, Promise<unknown>>();
|
|
53
59
|
|
|
54
60
|
function isManifestLike(value: unknown): value is Record<string, unknown> {
|
|
55
61
|
if (!value || typeof value !== "object") return false;
|
|
@@ -72,8 +78,10 @@ export function hasAllRequiredPlatforms(value: unknown): boolean {
|
|
|
72
78
|
return REQUIRED_PLATFORM_KEYS.every((k) => k in platforms);
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
async function fetchSignedManifest(
|
|
76
|
-
|
|
81
|
+
async function fetchSignedManifest(
|
|
82
|
+
channel: ClipsUpdateChannel,
|
|
83
|
+
): Promise<unknown> {
|
|
84
|
+
const res = await fetch(GITHUB_MANIFEST_URL[channel], {
|
|
77
85
|
headers: {
|
|
78
86
|
accept: "application/json",
|
|
79
87
|
"user-agent": "clips-updater-manifest",
|
|
@@ -94,38 +102,49 @@ async function fetchSignedManifest(): Promise<unknown> {
|
|
|
94
102
|
return json;
|
|
95
103
|
}
|
|
96
104
|
|
|
97
|
-
|
|
105
|
+
function normalizeChannel(value: unknown): ClipsUpdateChannel {
|
|
106
|
+
return value === "nightly" ? "nightly" : "production";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function getManifest(
|
|
110
|
+
channel: ClipsUpdateChannel = "production",
|
|
111
|
+
): Promise<unknown> {
|
|
98
112
|
const now = Date.now();
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
113
|
+
const cached = cache.get(channel);
|
|
114
|
+
if (cached && now - cached.ts < CACHE_TTL_MS) return cached.data;
|
|
115
|
+
const pending = inFlight.get(channel);
|
|
116
|
+
if (pending) return pending;
|
|
117
|
+
const request = (async () => {
|
|
102
118
|
try {
|
|
103
|
-
const data = await fetchSignedManifest();
|
|
104
|
-
cache
|
|
119
|
+
const data = await fetchSignedManifest(channel);
|
|
120
|
+
cache.set(channel, { data, ts: Date.now() });
|
|
105
121
|
return data;
|
|
106
122
|
} catch {
|
|
107
123
|
// A validation or network failure may serve the last good manifest (or
|
|
108
124
|
// inert fallback), but it must not make that fallback fresh again.
|
|
109
125
|
// Otherwise an incomplete release manifest can indefinitely extend the
|
|
110
126
|
// stale cache window on every failed refresh.
|
|
111
|
-
return cache?.data ?? INERT_MANIFEST;
|
|
127
|
+
return cache.get(channel)?.data ?? INERT_MANIFEST;
|
|
112
128
|
} finally {
|
|
113
|
-
inFlight
|
|
129
|
+
inFlight.delete(channel);
|
|
114
130
|
}
|
|
115
131
|
})();
|
|
116
|
-
|
|
132
|
+
inFlight.set(channel, request);
|
|
133
|
+
return request;
|
|
117
134
|
}
|
|
118
135
|
|
|
119
136
|
export const __clipsUpdaterTest = {
|
|
120
137
|
getManifest,
|
|
121
138
|
reset() {
|
|
122
|
-
cache
|
|
123
|
-
inFlight
|
|
139
|
+
cache.clear();
|
|
140
|
+
inFlight.clear();
|
|
124
141
|
},
|
|
125
142
|
};
|
|
126
143
|
|
|
127
144
|
export default defineEventHandler(async (event) => {
|
|
128
|
-
const
|
|
145
|
+
const query = getQuery(event);
|
|
146
|
+
const channel = normalizeChannel(query.channel);
|
|
147
|
+
const manifest = await getManifest(channel);
|
|
129
148
|
setResponseHeaders(event, {
|
|
130
149
|
"content-type": "application/json; charset=utf-8",
|
|
131
150
|
"cache-control": "public, max-age=60",
|
|
@@ -63,7 +63,7 @@ decisions, feedback, agent runs, and provider audit records.
|
|
|
63
63
|
| `evaluate-triage-item` | Append a decision. |
|
|
64
64
|
| `record-triage-feedback` | Capture human correction for learning. |
|
|
65
65
|
| `approve-factory-item` | Explicitly authorize one bounded run. |
|
|
66
|
-
| `start-builder-for-item` | Govern clear-bug dispatch through Slack or Builder API. |
|
|
66
|
+
| `start-builder-for-item` | Govern clear-bug dispatch through Slack or Builder API, or record a skip reason. |
|
|
67
67
|
| `govern-agent-native-pull-request` | Apply PR evidence and ownership gates. |
|
|
68
68
|
| `list-factory-automations` / `save-factory-automation` / `run-factory-automation` | Inspect or edit org-owned automations. |
|
|
69
69
|
| `list-factory-audit` | Inspect automation runs, evidence, decisions, and provider actions. |
|
|
@@ -71,7 +71,8 @@ decisions, feedback, agent runs, and provider audit records.
|
|
|
71
71
|
| `suggest-factory-rules` | Mine feedback into proposals. |
|
|
72
72
|
| `reconcile-triage-run` | Persist callback/provider reconciliation. |
|
|
73
73
|
| `list-factories` / `get-factory-graph` | Inspect definitions, versions, and metrics. |
|
|
74
|
-
| `save-factory-graph` | Create
|
|
74
|
+
| `save-factory-graph` | Create/version a graph with inspected `expectedGraphVersion`; never starts provider work. |
|
|
75
|
+
| graph history actions | Factory graph version history. |
|
|
75
76
|
| `list-factory-comments` / `add-factory-comment` | Read or attach comments to a canvas, node, or edge. |
|
|
76
77
|
| `provider-api-catalog` / `provider-api-docs` / `provider-api-request` | Use connected provider APIs with shared credentials; never request raw keys. |
|
|
77
78
|
| `list-workspace-apps` / `update-workspace-app-metadata` | Inventory and edit mounted apps. |
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core/action";
|
|
2
|
+
import { and, eq } from "drizzle-orm";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import { getDb } from "../server/db/index.js";
|
|
6
|
+
import { factoryGraphVersions } from "../server/db/schema.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_FACTORY_ID,
|
|
9
|
+
parseFactoryGraph,
|
|
10
|
+
readFactoryDefinition,
|
|
11
|
+
} from "../server/factory-graph/store.js";
|
|
12
|
+
import {
|
|
13
|
+
requireWorkspaceMember,
|
|
14
|
+
workspaceMemberIdentityFromContext,
|
|
15
|
+
} from "../server/lib/require-workspace-member.js";
|
|
16
|
+
|
|
17
|
+
export default defineAction({
|
|
18
|
+
description:
|
|
19
|
+
"Read one validated Factory visual graph version for history preview. The snapshot is scoped to the active workspace and does not change the current Factory.",
|
|
20
|
+
schema: z.object({
|
|
21
|
+
factoryId: z
|
|
22
|
+
.string()
|
|
23
|
+
.trim()
|
|
24
|
+
.min(1)
|
|
25
|
+
.max(120)
|
|
26
|
+
.regex(/^[a-z0-9][a-z0-9-]*$/)
|
|
27
|
+
.default(DEFAULT_FACTORY_ID),
|
|
28
|
+
versionId: z.string().trim().min(1).max(240),
|
|
29
|
+
}),
|
|
30
|
+
http: { method: "GET" },
|
|
31
|
+
readOnly: true,
|
|
32
|
+
parallelSafe: true,
|
|
33
|
+
run: async ({ factoryId, versionId }, context) => {
|
|
34
|
+
const { orgId } = await requireWorkspaceMember(
|
|
35
|
+
workspaceMemberIdentityFromContext(context),
|
|
36
|
+
);
|
|
37
|
+
const currentDefinition = await readFactoryDefinition(orgId, factoryId);
|
|
38
|
+
const currentVersion = currentDefinition?.graphVersion ?? null;
|
|
39
|
+
const row = (
|
|
40
|
+
await getDb()
|
|
41
|
+
.select()
|
|
42
|
+
.from(factoryGraphVersions)
|
|
43
|
+
.where(
|
|
44
|
+
and(
|
|
45
|
+
eq(factoryGraphVersions.id, versionId),
|
|
46
|
+
eq(factoryGraphVersions.factoryId, factoryId),
|
|
47
|
+
eq(factoryGraphVersions.orgId, orgId),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
.limit(1)
|
|
51
|
+
)[0];
|
|
52
|
+
|
|
53
|
+
if (!row) {
|
|
54
|
+
throw new Error("Factory graph version not found.");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
id: row.id,
|
|
59
|
+
factoryId: row.factoryId,
|
|
60
|
+
version: row.version,
|
|
61
|
+
graph: parseFactoryGraph(row.graphJson),
|
|
62
|
+
source: row.source,
|
|
63
|
+
changeSummary: row.changeSummary,
|
|
64
|
+
createdAt: row.createdAt,
|
|
65
|
+
createdBy: row.createdBy,
|
|
66
|
+
isCurrent: currentVersion === row.version,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -41,6 +41,10 @@ export default defineAction({
|
|
|
41
41
|
timezone: meta.timezone ?? null,
|
|
42
42
|
condition: meta.condition ?? null,
|
|
43
43
|
createdBy: meta.createdBy ?? null,
|
|
44
|
+
updatedAt:
|
|
45
|
+
Number.isFinite(resource.updatedAt) && resource.updatedAt > 0
|
|
46
|
+
? new Date(resource.updatedAt).toISOString()
|
|
47
|
+
: null,
|
|
44
48
|
canUpdate,
|
|
45
49
|
runs: await listAutomationRuns({
|
|
46
50
|
owners: [resource.owner],
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core/action";
|
|
2
|
+
import { and, desc, eq, lt } from "drizzle-orm";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import { getDb } from "../server/db/index.js";
|
|
6
|
+
import { factoryGraphVersions } from "../server/db/schema.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_FACTORY_ID,
|
|
9
|
+
readFactoryDefinition,
|
|
10
|
+
} from "../server/factory-graph/store.js";
|
|
11
|
+
import {
|
|
12
|
+
requireWorkspaceMember,
|
|
13
|
+
workspaceMemberIdentityFromContext,
|
|
14
|
+
} from "../server/lib/require-workspace-member.js";
|
|
15
|
+
|
|
16
|
+
export default defineAction({
|
|
17
|
+
description:
|
|
18
|
+
"List bounded saved visual graph version metadata for a Factory, newest first. Use get-factory-graph-version to read one validated snapshot for preview or restore.",
|
|
19
|
+
schema: z.object({
|
|
20
|
+
factoryId: z
|
|
21
|
+
.string()
|
|
22
|
+
.trim()
|
|
23
|
+
.min(1)
|
|
24
|
+
.max(120)
|
|
25
|
+
.regex(/^[a-z0-9][a-z0-9-]*$/)
|
|
26
|
+
.default(DEFAULT_FACTORY_ID),
|
|
27
|
+
limit: z.coerce.number().int().min(1).max(50).default(25),
|
|
28
|
+
beforeVersion: z.coerce.number().int().positive().optional(),
|
|
29
|
+
}),
|
|
30
|
+
http: { method: "GET" },
|
|
31
|
+
readOnly: true,
|
|
32
|
+
parallelSafe: true,
|
|
33
|
+
run: async ({ factoryId, limit, beforeVersion }, context) => {
|
|
34
|
+
const { orgId } = await requireWorkspaceMember(
|
|
35
|
+
workspaceMemberIdentityFromContext(context),
|
|
36
|
+
);
|
|
37
|
+
const currentDefinition = await readFactoryDefinition(orgId, factoryId);
|
|
38
|
+
const currentVersion = currentDefinition?.graphVersion ?? null;
|
|
39
|
+
const rows = await getDb()
|
|
40
|
+
.select({
|
|
41
|
+
id: factoryGraphVersions.id,
|
|
42
|
+
factoryId: factoryGraphVersions.factoryId,
|
|
43
|
+
version: factoryGraphVersions.version,
|
|
44
|
+
source: factoryGraphVersions.source,
|
|
45
|
+
changeSummary: factoryGraphVersions.changeSummary,
|
|
46
|
+
createdAt: factoryGraphVersions.createdAt,
|
|
47
|
+
createdBy: factoryGraphVersions.createdBy,
|
|
48
|
+
})
|
|
49
|
+
.from(factoryGraphVersions)
|
|
50
|
+
.where(
|
|
51
|
+
and(
|
|
52
|
+
eq(factoryGraphVersions.factoryId, factoryId),
|
|
53
|
+
eq(factoryGraphVersions.orgId, orgId),
|
|
54
|
+
beforeVersion === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: lt(factoryGraphVersions.version, beforeVersion),
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
.orderBy(desc(factoryGraphVersions.version))
|
|
60
|
+
.limit(limit + 1);
|
|
61
|
+
const page = rows.slice(0, limit);
|
|
62
|
+
const hasMore = rows.length > limit;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
factoryId,
|
|
66
|
+
currentVersion,
|
|
67
|
+
hasMore,
|
|
68
|
+
nextBeforeVersion:
|
|
69
|
+
hasMore && page.length > 0 ? page[page.length - 1].version : null,
|
|
70
|
+
versions: page.map((row) => ({
|
|
71
|
+
id: row.id,
|
|
72
|
+
factoryId: row.factoryId,
|
|
73
|
+
version: row.version,
|
|
74
|
+
source: row.source,
|
|
75
|
+
changeSummary: row.changeSummary,
|
|
76
|
+
createdAt: row.createdAt,
|
|
77
|
+
createdBy: row.createdBy,
|
|
78
|
+
isCurrent: currentVersion === row.version,
|
|
79
|
+
})),
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
});
|