@agent-native/core 0.163.0 → 0.163.2
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/client/session-replay.js +349 -100
- 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/collab/struct-routes.d.ts +1 -1
- package/dist/config.js +11 -1
- package/dist/deploy/build.d.ts +1 -1
- package/dist/deploy/build.js +89 -12
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- 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/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.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/server/transcribe-voice.d.ts +1 -1
- 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/collab/storage.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare function trySaveYDocState(docId: string, state: Uint8Array, textS
|
|
|
18
18
|
export declare function saveYDocState(docId: string, state: Uint8Array, textSnapshot: string): Promise<void>;
|
|
19
19
|
/** Check if a document has collaborative state. */
|
|
20
20
|
export declare function hasCollabState(docId: string): Promise<boolean>;
|
|
21
|
+
/** Load all existing document ids in one query for startup reconciliation. */
|
|
22
|
+
export declare function listCollabDocIds(): Promise<Set<string>>;
|
|
21
23
|
/** Delete collaborative state for a document. */
|
|
22
24
|
export declare function deleteCollabState(docId: string): Promise<void>;
|
|
23
25
|
declare function uint8ArrayToBase64(arr: Uint8Array): string;
|
package/dist/collab/storage.js
CHANGED
|
@@ -148,6 +148,13 @@ export async function hasCollabState(docId) {
|
|
|
148
148
|
});
|
|
149
149
|
return rows.length > 0;
|
|
150
150
|
}
|
|
151
|
+
/** Load all existing document ids in one query for startup reconciliation. */
|
|
152
|
+
export async function listCollabDocIds() {
|
|
153
|
+
await ensureTable();
|
|
154
|
+
const client = getDbExec();
|
|
155
|
+
const { rows } = await client.execute("SELECT doc_id FROM _collab_docs");
|
|
156
|
+
return new Set(rows.flatMap((row) => typeof row.doc_id === "string" && row.doc_id ? [row.doc_id] : []));
|
|
157
|
+
}
|
|
151
158
|
/** Delete collaborative state for a document. */
|
|
152
159
|
export async function deleteCollabState(docId) {
|
|
153
160
|
await ensureTable();
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error: string;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
package/dist/config.js
CHANGED
|
@@ -374,14 +374,24 @@ export function isAgentNativeDeploymentEnvironment(value) {
|
|
|
374
374
|
* never parses process.env itself.
|
|
375
375
|
*/
|
|
376
376
|
export function inferAgentNativeDeploymentEnvironment(env, mode) {
|
|
377
|
+
const explicit = env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT?.trim().toLowerCase();
|
|
378
|
+
if (explicit && !isAgentNativeDeploymentEnvironment(explicit)) {
|
|
379
|
+
throw new Error('AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT must be "local", "beta", "production", or "preview"');
|
|
380
|
+
}
|
|
381
|
+
if (isAgentNativeDeploymentEnvironment(explicit))
|
|
382
|
+
return explicit;
|
|
377
383
|
const context = env.CONTEXT?.trim().toLowerCase();
|
|
378
384
|
const branch = env.BRANCH?.trim().toLowerCase();
|
|
379
|
-
|
|
385
|
+
const vercelEnv = env.VERCEL_ENV?.trim().toLowerCase();
|
|
386
|
+
if (branch === "production" ||
|
|
387
|
+
(context === "production" && branch !== "beta")) {
|
|
380
388
|
return "production";
|
|
381
389
|
}
|
|
382
390
|
if (branch === "beta" || (context === "branch-deploy" && branch === "main")) {
|
|
383
391
|
return "beta";
|
|
384
392
|
}
|
|
393
|
+
if (vercelEnv === "preview")
|
|
394
|
+
return "preview";
|
|
385
395
|
if (context === "deploy-preview" ||
|
|
386
396
|
context === "branch-deploy" ||
|
|
387
397
|
branch?.startsWith("deploy-preview")) {
|
package/dist/deploy/build.d.ts
CHANGED
|
@@ -337,4 +337,4 @@ export declare function resolveNitroBundledYjsEntry(): string;
|
|
|
337
337
|
* small set above through the controlled post-build pass.
|
|
338
338
|
*/
|
|
339
339
|
export declare function nitroNoExternalsForPreset(targetPreset: string): true | readonly string[];
|
|
340
|
-
export declare function resolveNitroBuildReplacements(env?: NodeJS.ProcessEnv): Record<string, string>;
|
|
340
|
+
export declare function resolveNitroBuildReplacements(env?: NodeJS.ProcessEnv, deploymentEnvironment?: string): Record<string, string>;
|
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
|
|
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
-
error?: undefined;
|
|
21
20
|
configured?: undefined;
|
|
22
21
|
connectPath?: undefined;
|
|
23
22
|
url: string;
|
|
24
23
|
id: string;
|
|
25
24
|
provider: string;
|
|
25
|
+
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
@@ -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;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
ok?: undefined;
|
|
38
37
|
status?: undefined;
|
|
38
|
+
ok?: undefined;
|
|
39
39
|
} | {
|
|
40
|
-
error?: undefined;
|
|
41
40
|
ok: boolean;
|
|
42
41
|
status: string;
|
|
42
|
+
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
-
ok?: undefined;
|
|
45
44
|
error: string;
|
|
46
45
|
removed?: undefined;
|
|
46
|
+
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
|
-
error?: undefined;
|
|
49
48
|
ok: boolean;
|
|
50
49
|
removed: boolean;
|
|
50
|
+
error?: undefined;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
53
|
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
54
54
|
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
-
ok?: undefined;
|
|
58
57
|
error: string;
|
|
59
58
|
note?: undefined;
|
|
59
|
+
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
|
-
error?: undefined;
|
|
62
61
|
ok: boolean;
|
|
63
62
|
note?: undefined;
|
|
64
|
-
} | {
|
|
65
63
|
error?: undefined;
|
|
64
|
+
} | {
|
|
66
65
|
ok: boolean;
|
|
67
66
|
note: string;
|
|
67
|
+
error?: undefined;
|
|
68
68
|
} | {
|
|
69
69
|
note?: undefined;
|
|
70
70
|
ok: boolean;
|
|
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
|
|
|
95
95
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
96
96
|
error: string;
|
|
97
97
|
} | {
|
|
98
|
-
error?: undefined;
|
|
99
98
|
ok: boolean;
|
|
100
99
|
key: string;
|
|
101
|
-
} | {
|
|
102
100
|
error?: undefined;
|
|
101
|
+
} | {
|
|
103
102
|
ok: boolean;
|
|
104
103
|
removed: boolean;
|
|
104
|
+
error?: undefined;
|
|
105
105
|
}>>;
|
|
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
-
error?: undefined;
|
|
31
30
|
ok: boolean;
|
|
32
31
|
key: string;
|
|
33
32
|
baseUrlKey?: string;
|
|
34
33
|
scope: AgentEngineApiKeyScope;
|
|
34
|
+
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
|
@@ -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.2",
|
|
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": {
|