@agent-native/core 0.163.0 → 0.163.1
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/server/plugins/collab.ts +1 -0
- package/corpus/templates/slides/DEVELOPING.md +17 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +67 -0
- package/corpus/templates/slides/actions/request-deck-access.ts +569 -0
- package/corpus/templates/slides/agent-native.json +3 -0
- package/corpus/templates/slides/app/components/layout/Header.tsx +2 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +51 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +12 -0
- package/corpus/templates/slides/app/lib/deck-editor-loading.ts +7 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +172 -32
- package/corpus/templates/slides/changelog/2026-08-18-private-deck-links-now-explain-access-and-let-viewers-notify.md +6 -0
- package/corpus/templates/slides/server/db/schema.ts +10 -0
- package/corpus/templates/slides/server/plugins/db.ts +17 -0
- package/dist/client/analytics.d.ts +1 -0
- package/dist/client/analytics.js +19 -5
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +2 -0
- package/dist/collab/storage.js +7 -0
- package/dist/config.js +11 -1
- package/dist/deploy/build.d.ts +1 -1
- package/dist/deploy/build.js +89 -12
- package/dist/observability/routes.d.ts +1 -1
- package/dist/observability/tracking-identity.js +2 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/collab-plugin.d.ts +6 -0
- package/dist/server/collab-plugin.js +27 -6
- package/dist/server/deploy-environment.d.ts +1 -1
- package/dist/server/deploy-environment.js +40 -2
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/sentry-config.js +8 -4
- package/dist/server/sentry.js +4 -0
- package/dist/tracking/registry.js +8 -6
- package/dist/vite/client.js +5 -0
- package/docs/content/deployment.mdx +19 -5
- package/package.json +1 -1
package/dist/deploy/build.js
CHANGED
|
@@ -891,6 +891,77 @@ function isTruthyRuntimeValue(value) {
|
|
|
891
891
|
);
|
|
892
892
|
}
|
|
893
893
|
|
|
894
|
+
function normalizeExplicitDeploymentEnvironment(value) {
|
|
895
|
+
const normalized = firstNonEmpty(value)?.toLowerCase();
|
|
896
|
+
if (!normalized) return;
|
|
897
|
+
if (
|
|
898
|
+
normalized !== "local" &&
|
|
899
|
+
normalized !== "beta" &&
|
|
900
|
+
normalized !== "production" &&
|
|
901
|
+
normalized !== "preview"
|
|
902
|
+
) {
|
|
903
|
+
throw new Error(
|
|
904
|
+
'AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT must be "local", "beta", "production", or "preview"',
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
return normalized;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function normalizeFallbackDeploymentEnvironment(value) {
|
|
911
|
+
const normalized = firstNonEmpty(value)?.toLowerCase();
|
|
912
|
+
if (normalized === "development" || normalized === "test") return "local";
|
|
913
|
+
return normalized === "local" ||
|
|
914
|
+
normalized === "beta" ||
|
|
915
|
+
normalized === "production" ||
|
|
916
|
+
normalized === "preview"
|
|
917
|
+
? normalized
|
|
918
|
+
: undefined;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function resolveDeploymentEnvironment() {
|
|
922
|
+
const env = globalThis.process?.env || {};
|
|
923
|
+
const explicit = normalizeExplicitDeploymentEnvironment(
|
|
924
|
+
env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT,
|
|
925
|
+
);
|
|
926
|
+
if (explicit) return explicit;
|
|
927
|
+
|
|
928
|
+
const context = firstNonEmpty(
|
|
929
|
+
typeof env.CONTEXT === "string" ? env.CONTEXT : undefined,
|
|
930
|
+
typeof env.NETLIFY_CONTEXT === "string" ? env.NETLIFY_CONTEXT : undefined,
|
|
931
|
+
typeof env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT === "string"
|
|
932
|
+
? env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT
|
|
933
|
+
: undefined,
|
|
934
|
+
)?.toLowerCase();
|
|
935
|
+
const branch =
|
|
936
|
+
typeof env.BRANCH === "string" ? env.BRANCH.trim().toLowerCase() : "";
|
|
937
|
+
const vercelEnv = String(env.VERCEL_ENV || "").trim().toLowerCase();
|
|
938
|
+
const sentryEnvironment = firstNonEmpty(env.SENTRY_ENVIRONMENT);
|
|
939
|
+
if (branch === "beta") return "beta";
|
|
940
|
+
if (
|
|
941
|
+
branch === "production" ||
|
|
942
|
+
(context === "production" && branch !== "beta")
|
|
943
|
+
) {
|
|
944
|
+
return "production";
|
|
945
|
+
}
|
|
946
|
+
if (context === "branch-deploy" && branch === "main") return "beta";
|
|
947
|
+
if (
|
|
948
|
+
context === "deploy-preview" ||
|
|
949
|
+
context === "branch-deploy" ||
|
|
950
|
+
branch.startsWith("deploy-preview") ||
|
|
951
|
+
vercelEnv === "preview"
|
|
952
|
+
) {
|
|
953
|
+
return "preview";
|
|
954
|
+
}
|
|
955
|
+
if (!context && !branch && !vercelEnv && sentryEnvironment) {
|
|
956
|
+
return normalizeFallbackDeploymentEnvironment(sentryEnvironment) || "production";
|
|
957
|
+
}
|
|
958
|
+
return (
|
|
959
|
+
normalizeFallbackDeploymentEnvironment(firstNonEmpty(context, vercelEnv)) ||
|
|
960
|
+
normalizeFallbackDeploymentEnvironment(env.NODE_ENV) ||
|
|
961
|
+
"production"
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
|
|
894
965
|
function getSentryClientConfigScript() {
|
|
895
966
|
const env = globalThis.process?.env || {};
|
|
896
967
|
const key = firstNonEmpty(env.SENTRY_CLIENT_KEY, env.VITE_SENTRY_CLIENT_KEY);
|
|
@@ -909,16 +980,15 @@ function getSentryClientConfigScript() {
|
|
|
909
980
|
env.VITE_SENTRY_DSN,
|
|
910
981
|
env.SENTRY_DSN,
|
|
911
982
|
) || (key && projectId && host ? "https://" + key + "@" + host + "/" + projectId : undefined);
|
|
912
|
-
|
|
983
|
+
const deploymentEnvironment = resolveDeploymentEnvironment();
|
|
913
984
|
const config = {
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
) || "production",
|
|
985
|
+
...(dsn
|
|
986
|
+
? {
|
|
987
|
+
sentryDsn: dsn,
|
|
988
|
+
sentryEnvironment: deploymentEnvironment,
|
|
989
|
+
}
|
|
990
|
+
: {}),
|
|
991
|
+
deploymentEnvironment,
|
|
922
992
|
};
|
|
923
993
|
return (
|
|
924
994
|
'<script data-agent-native-sentry-config>' +
|
|
@@ -3742,7 +3812,9 @@ function createBrowserOnlyServerStubPlugin() {
|
|
|
3742
3812
|
},
|
|
3743
3813
|
};
|
|
3744
3814
|
}
|
|
3745
|
-
export function resolveNitroBuildReplacements(env = process.env) {
|
|
3815
|
+
export function resolveNitroBuildReplacements(env = process.env, deploymentEnvironment) {
|
|
3816
|
+
const configuredDeploymentEnvironment = deploymentEnvironment?.trim() ||
|
|
3817
|
+
env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT?.trim();
|
|
3746
3818
|
return {
|
|
3747
3819
|
// Netlify exposes DEPLOY_ID only while building. Embed it into the Nitro
|
|
3748
3820
|
// function so preview OAuth relays can target this immutable deployment
|
|
@@ -3755,7 +3827,12 @@ export function resolveNitroBuildReplacements(env = process.env) {
|
|
|
3755
3827
|
// a separate server build, so embed release migration ownership here as
|
|
3756
3828
|
// well as in the Vite server bundle.
|
|
3757
3829
|
"process.env.AGENT_NATIVE_RELEASE_MIGRATIONS": JSON.stringify(env.AGENT_NATIVE_RELEASE_MIGRATIONS?.trim() || ""),
|
|
3758
|
-
"process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(env.CONTEXT?.trim() || ""),
|
|
3830
|
+
"process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(env.CONTEXT?.trim() || env.NETLIFY_CONTEXT?.trim() || ""),
|
|
3831
|
+
...(configuredDeploymentEnvironment
|
|
3832
|
+
? {
|
|
3833
|
+
"process.env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT": JSON.stringify(configuredDeploymentEnvironment),
|
|
3834
|
+
}
|
|
3835
|
+
: {}),
|
|
3759
3836
|
};
|
|
3760
3837
|
}
|
|
3761
3838
|
async function buildWithNitro() {
|
|
@@ -3841,7 +3918,7 @@ export default bundle;
|
|
|
3841
3918
|
virtual: {
|
|
3842
3919
|
"virtual:agents-bundle": agentsBundleModuleSource,
|
|
3843
3920
|
},
|
|
3844
|
-
replace: resolveNitroBuildReplacements(),
|
|
3921
|
+
replace: resolveNitroBuildReplacements(process.env, nitroAgentConfig.deployment?.environment),
|
|
3845
3922
|
// Replace browser-only renderers (Excalidraw/Mermaid) with an inert proxy in
|
|
3846
3923
|
// the server bundle. Without this, Nitro's Rolldown build pulls the real
|
|
3847
3924
|
// Excalidraw into a shared vendor chunk imported statically by the SSR render
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveDeployEnvironment } from "../server/deploy-environment.js";
|
|
1
2
|
function normalizeTrackingSlug(value) {
|
|
2
3
|
const raw = value?.trim().toLowerCase();
|
|
3
4
|
if (!raw)
|
|
@@ -44,6 +45,7 @@ export function trackingIdentityProperties() {
|
|
|
44
45
|
normalizeTrackingSlug(process.env.VITE_APP_TEMPLATE) ||
|
|
45
46
|
app;
|
|
46
47
|
return {
|
|
48
|
+
deployment_environment: resolveDeployEnvironment(),
|
|
47
49
|
...(app ? { app, agent_native_app: app } : {}),
|
|
48
50
|
...(template ? { template, agent_native_template: template } : {}),
|
|
49
51
|
};
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
ok?: undefined;
|
|
52
51
|
error: string;
|
|
52
|
+
ok?: undefined;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
|
@@ -41,6 +41,8 @@ export interface CollabPluginOptions {
|
|
|
41
41
|
idColumn?: string;
|
|
42
42
|
/** Whether to auto-seed existing documents on startup. Default: true */
|
|
43
43
|
autoSeed?: boolean;
|
|
44
|
+
/** Map a source-table id to the id used by the collab document store. */
|
|
45
|
+
resolveCollabDocumentId?: (sourceId: string) => string;
|
|
44
46
|
/**
|
|
45
47
|
* Callback invoked after a collab update to sync the content column.
|
|
46
48
|
* If not provided, the plugin auto-syncs using table/contentColumn/idColumn.
|
|
@@ -78,4 +80,8 @@ export interface CollabPluginOptions {
|
|
|
78
80
|
}
|
|
79
81
|
export declare function normalizeCollabAccess(options: Pick<CollabPluginOptions, "access" | "resourceType" | "resolveResourceId">): NormalizedCollabAccess;
|
|
80
82
|
export declare function createCollabPlugin(options?: CollabPluginOptions): NitroPluginDef;
|
|
83
|
+
export declare function selectUnseededCollabRows(rows: ReadonlyArray<Record<string, unknown>>, idColumn: string, existingDocIds: ReadonlySet<string>, resolveCollabDocumentId?: (sourceId: string) => string): Array<{
|
|
84
|
+
row: Record<string, unknown>;
|
|
85
|
+
docId: string;
|
|
86
|
+
}>;
|
|
81
87
|
export {};
|
|
@@ -16,7 +16,7 @@ import { defineEventHandler, getMethod, setResponseStatus, } from "h3";
|
|
|
16
16
|
import { postAwareness, getActiveUsers } from "../collab/awareness.js";
|
|
17
17
|
import { getCollabEmitter } from "../collab/emitter.js";
|
|
18
18
|
import { getCollabState, postCollabUpdate, postCollabText, postCollabSearchReplace, } from "../collab/routes.js";
|
|
19
|
-
import {
|
|
19
|
+
import { listCollabDocIds } from "../collab/storage.js";
|
|
20
20
|
import { postCollabJson, getCollabJson, postCollabPatch, } from "../collab/struct-routes.js";
|
|
21
21
|
import { seedFromText, seedFromJson } from "../collab/ydoc-manager.js";
|
|
22
22
|
import { getDbExec } from "../db/client.js";
|
|
@@ -82,6 +82,7 @@ function warnForImplicitAllAuthenticatedAccess(table) {
|
|
|
82
82
|
export function createCollabPlugin(options = {}) {
|
|
83
83
|
const normalizedAccess = normalizeCollabAccess(options);
|
|
84
84
|
const { table = "documents", contentColumn = "content", idColumn = "id", autoSeed = true, maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES, } = options;
|
|
85
|
+
const resolveCollabDocumentId = options.resolveCollabDocumentId ?? ((sourceId) => sourceId);
|
|
85
86
|
const resourceType = normalizedAccess.mode === "resource"
|
|
86
87
|
? normalizedAccess.resourceType
|
|
87
88
|
: undefined;
|
|
@@ -308,13 +309,14 @@ export function createCollabPlugin(options = {}) {
|
|
|
308
309
|
// Run in background so it doesn't block startup
|
|
309
310
|
setTimeout(async () => {
|
|
310
311
|
try {
|
|
312
|
+
// Read existing ids once, then apply the plugin's document-id
|
|
313
|
+
// mapping before filtering. A source-table SQL predicate can use
|
|
314
|
+
// the wrong id for integrations such as Analytics' dash-* docs.
|
|
315
|
+
const existingDocIds = await listCollabDocIds();
|
|
311
316
|
const client = getDbExec();
|
|
312
317
|
const { rows } = await client.execute(`SELECT ${idColumn}, ${seedColumn} FROM ${table}`);
|
|
313
|
-
for (const row of rows) {
|
|
314
|
-
|
|
315
|
-
const exists = await hasCollabState(docId);
|
|
316
|
-
if (exists)
|
|
317
|
-
continue;
|
|
318
|
+
for (const { row, docId } of selectUnseededCollabRows(rows, idColumn, existingDocIds, resolveCollabDocumentId)) {
|
|
319
|
+
let seeded = false;
|
|
318
320
|
if (isJson) {
|
|
319
321
|
const raw = row[seedColumn] ?? "{}";
|
|
320
322
|
try {
|
|
@@ -323,6 +325,7 @@ export function createCollabPlugin(options = {}) {
|
|
|
323
325
|
? "array"
|
|
324
326
|
: "map";
|
|
325
327
|
await seedFromJson(docId, parsed, "data", inferredType);
|
|
328
|
+
seeded = true;
|
|
326
329
|
}
|
|
327
330
|
catch {
|
|
328
331
|
// Invalid JSON — skip
|
|
@@ -331,7 +334,10 @@ export function createCollabPlugin(options = {}) {
|
|
|
331
334
|
else {
|
|
332
335
|
const content = row[seedColumn] ?? "";
|
|
333
336
|
await seedFromText(docId, content);
|
|
337
|
+
seeded = true;
|
|
334
338
|
}
|
|
339
|
+
if (seeded)
|
|
340
|
+
existingDocIds.add(docId);
|
|
335
341
|
}
|
|
336
342
|
}
|
|
337
343
|
catch {
|
|
@@ -341,3 +347,18 @@ export function createCollabPlugin(options = {}) {
|
|
|
341
347
|
}
|
|
342
348
|
};
|
|
343
349
|
}
|
|
350
|
+
export function selectUnseededCollabRows(rows, idColumn, existingDocIds, resolveCollabDocumentId = (sourceId) => sourceId) {
|
|
351
|
+
const seenDocIds = new Set(existingDocIds);
|
|
352
|
+
const unseeded = [];
|
|
353
|
+
for (const row of rows) {
|
|
354
|
+
const sourceId = String(row[idColumn] ?? "");
|
|
355
|
+
if (!sourceId)
|
|
356
|
+
continue;
|
|
357
|
+
const docId = resolveCollabDocumentId(sourceId);
|
|
358
|
+
if (seenDocIds.has(docId))
|
|
359
|
+
continue;
|
|
360
|
+
seenDocIds.add(docId);
|
|
361
|
+
unseeded.push({ row, docId });
|
|
362
|
+
}
|
|
363
|
+
return unseeded;
|
|
364
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* not the vendor, and a second backend that reports errors without them
|
|
6
6
|
* produces issues nobody can tie to a release.
|
|
7
7
|
*/
|
|
8
|
-
/** The deploy environment name, e.g. `production`, `
|
|
8
|
+
/** The deploy environment name, e.g. `production`, `beta`, or `preview`. */
|
|
9
9
|
export declare function resolveDeployEnvironment(): string;
|
|
10
10
|
/**
|
|
11
11
|
* Resolve the agent-native version baked into core's package.json so the
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import fs from "node:fs";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { isAgentNativeDeploymentEnvironment } from "../config.js";
|
|
11
12
|
function firstNonEmpty(...values) {
|
|
12
13
|
for (const value of values) {
|
|
13
14
|
const trimmed = value?.trim();
|
|
@@ -16,9 +17,46 @@ function firstNonEmpty(...values) {
|
|
|
16
17
|
}
|
|
17
18
|
return undefined;
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
+
function normalizeFallbackEnvironment(value) {
|
|
21
|
+
const normalized = firstNonEmpty(value)?.toLowerCase();
|
|
22
|
+
if (normalized === "development" || normalized === "test")
|
|
23
|
+
return "local";
|
|
24
|
+
return isAgentNativeDeploymentEnvironment(normalized)
|
|
25
|
+
? normalized
|
|
26
|
+
: undefined;
|
|
27
|
+
}
|
|
28
|
+
/** The deploy environment name, e.g. `production`, `beta`, or `preview`. */
|
|
20
29
|
export function resolveDeployEnvironment() {
|
|
21
|
-
|
|
30
|
+
const explicit = firstNonEmpty(process.env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT)?.toLowerCase();
|
|
31
|
+
if (explicit) {
|
|
32
|
+
if (!isAgentNativeDeploymentEnvironment(explicit)) {
|
|
33
|
+
throw new Error('AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT must be "local", "beta", "production", or "preview"');
|
|
34
|
+
}
|
|
35
|
+
return explicit;
|
|
36
|
+
}
|
|
37
|
+
const context = firstNonEmpty(process.env.CONTEXT, process.env.NETLIFY_CONTEXT, process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT)?.toLowerCase();
|
|
38
|
+
const branch = process.env.BRANCH?.trim().toLowerCase();
|
|
39
|
+
const vercelEnv = process.env.VERCEL_ENV?.trim().toLowerCase();
|
|
40
|
+
if (branch === "beta")
|
|
41
|
+
return "beta";
|
|
42
|
+
if (branch === "production" ||
|
|
43
|
+
(context === "production" && branch !== "beta")) {
|
|
44
|
+
return "production";
|
|
45
|
+
}
|
|
46
|
+
if (context === "branch-deploy" && branch === "main")
|
|
47
|
+
return "beta";
|
|
48
|
+
if (context === "deploy-preview" ||
|
|
49
|
+
context === "branch-deploy" ||
|
|
50
|
+
branch?.startsWith("deploy-preview") ||
|
|
51
|
+
vercelEnv === "preview") {
|
|
52
|
+
return "preview";
|
|
53
|
+
}
|
|
54
|
+
if (!context && !branch && !vercelEnv) {
|
|
55
|
+
return (normalizeFallbackEnvironment(firstNonEmpty(process.env.SENTRY_ENVIRONMENT, process.env.NODE_ENV)) ?? "production");
|
|
56
|
+
}
|
|
57
|
+
return (normalizeFallbackEnvironment(firstNonEmpty(context, vercelEnv)) ??
|
|
58
|
+
normalizeFallbackEnvironment(process.env.NODE_ENV) ??
|
|
59
|
+
"production");
|
|
22
60
|
}
|
|
23
61
|
/**
|
|
24
62
|
* Resolve the agent-native version baked into core's package.json so the
|
|
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
-
error?: undefined;
|
|
30
29
|
token: string;
|
|
31
30
|
expiresAt: string;
|
|
32
31
|
ttlSeconds: number;
|
|
32
|
+
error?: undefined;
|
|
33
33
|
}>>;
|
|
@@ -28,11 +28,15 @@ export function resolvePublicSentryDsn() {
|
|
|
28
28
|
}
|
|
29
29
|
export function getSentryClientConfigScript() {
|
|
30
30
|
const dsn = resolvePublicSentryDsn();
|
|
31
|
-
|
|
32
|
-
return null;
|
|
31
|
+
const deploymentEnvironment = resolveDeployEnvironment();
|
|
33
32
|
const config = {
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
...(dsn
|
|
34
|
+
? {
|
|
35
|
+
sentryDsn: dsn,
|
|
36
|
+
sentryEnvironment: resolveSentryEnvironment(),
|
|
37
|
+
}
|
|
38
|
+
: {}),
|
|
39
|
+
deploymentEnvironment,
|
|
36
40
|
};
|
|
37
41
|
return [
|
|
38
42
|
"<script data-agent-native-sentry-config>",
|
package/dist/server/sentry.js
CHANGED
|
@@ -62,6 +62,10 @@ export function initServerSentry() {
|
|
|
62
62
|
// cookies, or process.env contents to Sentry without explicit consent.
|
|
63
63
|
sendDefaultPii: false,
|
|
64
64
|
beforeSend(event) {
|
|
65
|
+
event.tags = {
|
|
66
|
+
...event.tags,
|
|
67
|
+
deployment_environment: resolveDeployEnvironment(),
|
|
68
|
+
};
|
|
65
69
|
// Drop rules live in `error-noise-filter.ts` so every backend applies
|
|
66
70
|
// the same ones — they describe which server errors are non-bugs in
|
|
67
71
|
// this framework, not a Sentry preference.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveDeployEnvironment } from "../server/deploy-environment.js";
|
|
1
2
|
import { getRequestContext } from "../server/request-context.js";
|
|
2
3
|
import { ANALYTICS_CLIENT_PLATFORM_PROPERTY } from "../shared/analytics-platform.js";
|
|
3
4
|
const REGISTRY_KEY = Symbol.for("@agent-native/core/tracking.registry");
|
|
@@ -46,12 +47,13 @@ function resolveTrackingSource(source) {
|
|
|
46
47
|
export function track(name, properties, source) {
|
|
47
48
|
const { userId, anonymousId, sessionId } = resolveTrackingSource(source);
|
|
48
49
|
const clientPlatform = getRequestContext()?.clientPlatform;
|
|
49
|
-
const trackedProperties =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
const trackedProperties = {
|
|
51
|
+
...(properties ?? {}),
|
|
52
|
+
deployment_environment: resolveDeployEnvironment(),
|
|
53
|
+
...(clientPlatform
|
|
54
|
+
? { [ANALYTICS_CLIENT_PLATFORM_PROPERTY]: clientPlatform }
|
|
55
|
+
: {}),
|
|
56
|
+
};
|
|
55
57
|
const event = {
|
|
56
58
|
name,
|
|
57
59
|
properties: trackedProperties,
|
package/dist/vite/client.js
CHANGED
|
@@ -2913,6 +2913,11 @@ function createAgentNativeConfig(options = {}, command, userConfig = {}, mode =
|
|
|
2913
2913
|
// netlify.toml environment is available to the build but not injected
|
|
2914
2914
|
// into deployed Functions, so embed the decision in the server bundle.
|
|
2915
2915
|
"process.env.AGENT_NATIVE_RELEASE_MIGRATIONS": JSON.stringify(process.env.AGENT_NATIVE_RELEASE_MIGRATIONS?.trim() || ""),
|
|
2916
|
+
...(resolvedAppConfig.deployment?.environment
|
|
2917
|
+
? {
|
|
2918
|
+
"process.env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT": JSON.stringify(resolvedAppConfig.deployment.environment),
|
|
2919
|
+
}
|
|
2920
|
+
: {}),
|
|
2916
2921
|
__AGENT_NATIVE_BUILD_GTM_CONTAINER_ID__: JSON.stringify(process.env.GTM_CONTAINER_ID?.trim() || ""),
|
|
2917
2922
|
"process.env.AGENT_NATIVE_BUILD_GTM_CONTAINER_ID": JSON.stringify(process.env.GTM_CONTAINER_ID?.trim() || ""),
|
|
2918
2923
|
// Framework route warmup controls how SSR `.data` routes are fetched:
|
|
@@ -26,11 +26,11 @@ pnpm install
|
|
|
26
26
|
|
|
27
27
|
The install step creates the lockfile that the production Dockerfile below copies into its build stage.
|
|
28
28
|
|
|
29
|
-
### 2. Add
|
|
29
|
+
### 2. Add the local Docker files
|
|
30
30
|
|
|
31
|
-
Create `docker-compose.yml` in the app root.
|
|
31
|
+
Create `Dockerfile`, `.dockerignore`, and `docker-compose.yml` in the app root. `docker compose up --build` needs the Dockerfile, and `.dockerignore` keeps host-only files such as `node_modules` out of the Linux build context. Compose starts Postgres only on the private Compose network.
|
|
32
32
|
|
|
33
|
-
You can also download the [Dockerfile](https://www.agent-native.com/examples/self-hosted-chat/Dockerfile), [Compose file](https://www.agent-native.com/examples/self-hosted-chat/docker-compose.yml), and [environment template](https://www.agent-native.com/examples/self-hosted-chat/env.example) as a starter fixture.
|
|
33
|
+
You can also download the [Dockerfile](https://www.agent-native.com/examples/self-hosted-chat/Dockerfile), [.dockerignore](https://www.agent-native.com/examples/self-hosted-chat/.dockerignore), [Compose file](https://www.agent-native.com/examples/self-hosted-chat/docker-compose.yml), and [environment template](https://www.agent-native.com/examples/self-hosted-chat/env.example) as a starter fixture. The [Dockerfile](#docker) below matches the fixture.
|
|
34
34
|
|
|
35
35
|
```yaml filename="docker-compose.yml" maxLines=40
|
|
36
36
|
services:
|
|
@@ -53,7 +53,7 @@ services:
|
|
|
53
53
|
POSTGRES_USER: agent_native
|
|
54
54
|
POSTGRES_HOST_AUTH_METHOD: trust
|
|
55
55
|
volumes:
|
|
56
|
-
- postgres-data:/var/lib/postgresql
|
|
56
|
+
- postgres-data-v18:/var/lib/postgresql
|
|
57
57
|
healthcheck:
|
|
58
58
|
test: ["CMD-SHELL", "pg_isready -U agent_native -d agent_native"]
|
|
59
59
|
interval: 5s
|
|
@@ -61,9 +61,11 @@ services:
|
|
|
61
61
|
retries: 10
|
|
62
62
|
|
|
63
63
|
volumes:
|
|
64
|
-
postgres-data:
|
|
64
|
+
postgres-data-v18:
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
PostgreSQL 18 uses `/var/lib/postgresql` as its volume mount path, unlike PostgreSQL 17 and earlier. The versioned volume name keeps this fresh fixture separate from older local stacks. If you are upgrading an existing PostgreSQL 17 or earlier stack, back up and migrate its data before changing the image or mount path. Do not point this fixture at the old volume without a migration.
|
|
68
|
+
|
|
67
69
|
### 3. Run it
|
|
68
70
|
|
|
69
71
|
```bash
|
|
@@ -322,6 +324,18 @@ EXPOSE 3000
|
|
|
322
324
|
CMD ["node", ".output/server/index.mjs"]
|
|
323
325
|
```
|
|
324
326
|
|
|
327
|
+
Create `.dockerignore` alongside the Dockerfile:
|
|
328
|
+
|
|
329
|
+
```text filename=".dockerignore"
|
|
330
|
+
node_modules
|
|
331
|
+
.output
|
|
332
|
+
data
|
|
333
|
+
.env
|
|
334
|
+
.env.*
|
|
335
|
+
!.env.example
|
|
336
|
+
.git
|
|
337
|
+
```
|
|
338
|
+
|
|
325
339
|
### Self-hosted workspace with Docker Compose {#workspace-docker-compose}
|
|
326
340
|
|
|
327
341
|
The Dockerfile above is for one standalone app. A workspace is not one Nitro
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.163.
|
|
3
|
+
"version": "0.163.1",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|