@agent-native/core 0.8.1 → 0.9.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/dist/agent/run-manager.d.ts +10 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +77 -4
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +4 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +6 -5
- package/dist/agent/run-store.js.map +1 -1
- package/dist/cli/create.d.ts +26 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +62 -18
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +177 -22
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/workspace-dev.js +66 -5
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +2 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +4 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +38 -84
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +122 -15
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +14 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +34 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +21 -15
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +12 -11
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +5 -4
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +9 -8
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
- package/dist/client/dev-overlay/DevOverlay.js +4 -3
- package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +2 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionEditor.js +2 -1
- package/dist/client/extensions/ExtensionEditor.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +2 -1
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +4 -3
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +10 -9
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationCard.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationCard.js +2 -1
- package/dist/client/integrations/IntegrationCard.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +3 -2
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +3 -2
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
- package/dist/client/onboarding/SetupButton.js +14 -13
- package/dist/client/onboarding/SetupButton.js.map +1 -1
- package/dist/client/org/InvitationBanner.d.ts +8 -2
- package/dist/client/org/InvitationBanner.d.ts.map +1 -1
- package/dist/client/org/InvitationBanner.js +27 -6
- package/dist/client/org/InvitationBanner.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +29 -5
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +7 -6
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
- package/dist/client/resources/ResourceEditor.js +2 -1
- package/dist/client/resources/ResourceEditor.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +9 -9
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/AgentsSection.d.ts.map +1 -1
- package/dist/client/settings/AgentsSection.js +8 -7
- package/dist/client/settings/AgentsSection.js.map +1 -1
- package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
- package/dist/client/settings/AutomationsSection.js +4 -3
- package/dist/client/settings/AutomationsSection.js.map +1 -1
- package/dist/client/settings/SecretsSection.d.ts.map +1 -1
- package/dist/client/settings/SecretsSection.js +2 -1
- package/dist/client/settings/SecretsSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +3 -2
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +45 -4
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/theme.d.ts +4 -0
- package/dist/client/theme.d.ts.map +1 -0
- package/dist/client/theme.js +13 -0
- package/dist/client/theme.js.map +1 -0
- package/dist/client/use-session.d.ts.map +1 -1
- package/dist/client/use-session.js +14 -2
- package/dist/client/use-session.js.map +1 -1
- package/dist/collab/client.d.ts +1 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +18 -1
- package/dist/collab/client.js.map +1 -1
- package/dist/org/auto-join-domain.d.ts +28 -0
- package/dist/org/auto-join-domain.d.ts.map +1 -0
- package/dist/org/auto-join-domain.js +92 -0
- package/dist/org/auto-join-domain.js.map +1 -0
- package/dist/org/index.d.ts +2 -0
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +1 -0
- package/dist/org/index.js.map +1 -1
- package/dist/scripts/db/exec.d.ts.map +1 -1
- package/dist/scripts/db/exec.js +27 -1
- package/dist/scripts/db/exec.js.map +1 -1
- package/dist/scripts/db/index.d.ts.map +1 -1
- package/dist/scripts/db/index.js +1 -0
- package/dist/scripts/db/index.js.map +1 -1
- package/dist/scripts/db/reset-dev-owner.d.ts +27 -0
- package/dist/scripts/db/reset-dev-owner.d.ts.map +1 -0
- package/dist/scripts/db/reset-dev-owner.js +225 -0
- package/dist/scripts/db/reset-dev-owner.js.map +1 -0
- package/dist/scripts/db/scoping.d.ts.map +1 -1
- package/dist/scripts/db/scoping.js +15 -30
- package/dist/scripts/db/scoping.js.map +1 -1
- package/dist/scripts/dev-session.d.ts +46 -0
- package/dist/scripts/dev-session.d.ts.map +1 -0
- package/dist/scripts/dev-session.js +81 -0
- package/dist/scripts/dev-session.js.map +1 -0
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +21 -0
- package/dist/scripts/runner.js.map +1 -1
- package/dist/secrets/register.d.ts +1 -1
- package/dist/secrets/register.d.ts.map +1 -1
- package/dist/secrets/register.js +4 -2
- package/dist/secrets/register.js.map +1 -1
- package/dist/secrets/routes.d.ts.map +1 -1
- package/dist/secrets/routes.js +32 -0
- package/dist/secrets/routes.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +11 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +56 -13
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +47 -4
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +105 -29
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/design-token-utils.d.ts +13 -2
- package/dist/server/design-token-utils.d.ts.map +1 -1
- package/dist/server/design-token-utils.js +48 -16
- package/dist/server/design-token-utils.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +97 -8
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/templates/default/app/root.tsx +4 -0
- package/dist/templates/default/app/routes/_index.tsx +3 -2
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +76 -34
- package/dist/vite/client.js.map +1 -1
- package/package.json +1 -1
- package/src/templates/default/app/root.tsx +4 -0
- package/src/templates/default/app/routes/_index.tsx +3 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { getDbExec } from "../db/client.js";
|
|
2
|
+
import { getUserSetting, putUserSetting } from "../settings/user-settings.js";
|
|
3
|
+
const nanoid = () => globalThis.crypto?.randomUUID?.().replace(/-/g, "") ??
|
|
4
|
+
Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
5
|
+
/**
|
|
6
|
+
* Auto-join a newly-signed-up user into every org whose `allowed_domain`
|
|
7
|
+
* matches their email domain.
|
|
8
|
+
*
|
|
9
|
+
* Called from the Better Auth `user.create.after` hook so that e.g. a new
|
|
10
|
+
* `@builder.io` signup lands inside the existing Builder.io org on first
|
|
11
|
+
* page load instead of starting in Personal and having to find the join
|
|
12
|
+
* CTA. The org's owner opts into this by setting
|
|
13
|
+
* `organizations.allowed_domain` — the column already gated the manual
|
|
14
|
+
* "Join your team" UI in the picker; we use the same opt-in to drive
|
|
15
|
+
* automatic join.
|
|
16
|
+
*
|
|
17
|
+
* Idempotent — skips orgs the user is already a member of and never
|
|
18
|
+
* overwrites an existing `active-org-id` setting.
|
|
19
|
+
*
|
|
20
|
+
* Safe to call when the org tables don't exist (some templates don't use
|
|
21
|
+
* the org module): it swallows the "no such table" error and returns
|
|
22
|
+
* empty. Never throws — the caller is a signup hook and we don't want to
|
|
23
|
+
* block a user from creating their account because of an org-tier issue.
|
|
24
|
+
*/
|
|
25
|
+
export async function autoJoinDomainMatchingOrgs(rawEmail) {
|
|
26
|
+
const email = rawEmail.trim().toLowerCase();
|
|
27
|
+
if (!email)
|
|
28
|
+
return { joined: [], activeOrgId: null };
|
|
29
|
+
const domain = email.split("@")[1]?.toLowerCase();
|
|
30
|
+
if (!domain)
|
|
31
|
+
return { joined: [], activeOrgId: null };
|
|
32
|
+
const db = getDbExec();
|
|
33
|
+
let matches = [];
|
|
34
|
+
try {
|
|
35
|
+
const res = await db.execute({
|
|
36
|
+
sql: `SELECT o.id AS "orgId"
|
|
37
|
+
FROM organizations o
|
|
38
|
+
WHERE LOWER(o.allowed_domain) = ?
|
|
39
|
+
AND NOT EXISTS (
|
|
40
|
+
SELECT 1
|
|
41
|
+
FROM org_members m
|
|
42
|
+
WHERE m.org_id = o.id
|
|
43
|
+
AND LOWER(m.email) = ?
|
|
44
|
+
)
|
|
45
|
+
ORDER BY o.created_at ASC`,
|
|
46
|
+
args: [domain, email],
|
|
47
|
+
});
|
|
48
|
+
matches = res.rows.map((r) => ({
|
|
49
|
+
orgId: String(r.orgId ?? r.org_id),
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Template without org tables (or `allowed_domain` column not yet
|
|
54
|
+
// migrated). Not fatal — return empty.
|
|
55
|
+
return { joined: [], activeOrgId: null };
|
|
56
|
+
}
|
|
57
|
+
if (matches.length === 0)
|
|
58
|
+
return { joined: [], activeOrgId: null };
|
|
59
|
+
const joined = [];
|
|
60
|
+
for (const m of matches) {
|
|
61
|
+
try {
|
|
62
|
+
await db.execute({
|
|
63
|
+
sql: `INSERT INTO org_members (id, org_id, email, role, joined_at) VALUES (?, ?, ?, 'member', ?)`,
|
|
64
|
+
args: [nanoid(), m.orgId, email, Date.now()],
|
|
65
|
+
});
|
|
66
|
+
joined.push({ orgId: m.orgId });
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Race with a parallel join (e.g. user accepted an invite to the
|
|
70
|
+
// same org milliseconds earlier). The unique constraint keeps the
|
|
71
|
+
// existing membership intact; just skip this org.
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Set active-org-id to the first match only if the user doesn't
|
|
75
|
+
// already have one (a pending invite that ran first may have set it).
|
|
76
|
+
let activeOrgId = null;
|
|
77
|
+
if (joined[0]) {
|
|
78
|
+
try {
|
|
79
|
+
const existing = await getUserSetting(email, "active-org-id");
|
|
80
|
+
const hasActive = Boolean(existing?.orgId);
|
|
81
|
+
if (!hasActive) {
|
|
82
|
+
activeOrgId = joined[0].orgId;
|
|
83
|
+
await putUserSetting(email, "active-org-id", { orgId: activeOrgId });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// settings table missing — not fatal.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { joined, activeOrgId };
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=auto-join-domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-join-domain.js","sourceRoot":"","sources":["../../src/org/auto-join-domain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9E,MAAM,MAAM,GAAG,GAAW,EAAE,CAC1B,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;IACnD,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAOhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,QAAgB;IAEhB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAErD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAEtD,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAEvB,IAAI,OAAO,GAA6B,EAAE,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YAC3B,GAAG,EAAE;;;;;;;;;sCAS2B;YAChC,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;SACtB,CAAC,CAAC;QACH,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;YAClC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;SACnC,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;QAClE,uCAAuC;QACvC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAEnE,MAAM,MAAM,GAAmC,EAAE,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,CAAC;gBACf,GAAG,EAAE,4FAA4F;gBACjG,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;aAC7C,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;YACjE,kEAAkE;YAClE,kDAAkD;QACpD,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,sEAAsE;IACtE,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACd,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;YAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC3C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;gBAC9B,MAAM,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjC,CAAC","sourcesContent":["import { getDbExec } from \"../db/client.js\";\nimport { getUserSetting, putUserSetting } from \"../settings/user-settings.js\";\n\nconst nanoid = (): string =>\n globalThis.crypto?.randomUUID?.().replace(/-/g, \"\") ??\n Math.random().toString(36).slice(2) + Date.now().toString(36);\n\nexport interface AutoJoinDomainResult {\n joined: Array<{ orgId: string }>;\n activeOrgId: string | null;\n}\n\n/**\n * Auto-join a newly-signed-up user into every org whose `allowed_domain`\n * matches their email domain.\n *\n * Called from the Better Auth `user.create.after` hook so that e.g. a new\n * `@builder.io` signup lands inside the existing Builder.io org on first\n * page load instead of starting in Personal and having to find the join\n * CTA. The org's owner opts into this by setting\n * `organizations.allowed_domain` — the column already gated the manual\n * \"Join your team\" UI in the picker; we use the same opt-in to drive\n * automatic join.\n *\n * Idempotent — skips orgs the user is already a member of and never\n * overwrites an existing `active-org-id` setting.\n *\n * Safe to call when the org tables don't exist (some templates don't use\n * the org module): it swallows the \"no such table\" error and returns\n * empty. Never throws — the caller is a signup hook and we don't want to\n * block a user from creating their account because of an org-tier issue.\n */\nexport async function autoJoinDomainMatchingOrgs(\n rawEmail: string,\n): Promise<AutoJoinDomainResult> {\n const email = rawEmail.trim().toLowerCase();\n if (!email) return { joined: [], activeOrgId: null };\n\n const domain = email.split(\"@\")[1]?.toLowerCase();\n if (!domain) return { joined: [], activeOrgId: null };\n\n const db = getDbExec();\n\n let matches: Array<{ orgId: string }> = [];\n try {\n const res = await db.execute({\n sql: `SELECT o.id AS \"orgId\"\n FROM organizations o\n WHERE LOWER(o.allowed_domain) = ?\n AND NOT EXISTS (\n SELECT 1\n FROM org_members m\n WHERE m.org_id = o.id\n AND LOWER(m.email) = ?\n )\n ORDER BY o.created_at ASC`,\n args: [domain, email],\n });\n matches = res.rows.map((r: any) => ({\n orgId: String(r.orgId ?? r.org_id),\n }));\n } catch {\n // Template without org tables (or `allowed_domain` column not yet\n // migrated). Not fatal — return empty.\n return { joined: [], activeOrgId: null };\n }\n\n if (matches.length === 0) return { joined: [], activeOrgId: null };\n\n const joined: AutoJoinDomainResult[\"joined\"] = [];\n for (const m of matches) {\n try {\n await db.execute({\n sql: `INSERT INTO org_members (id, org_id, email, role, joined_at) VALUES (?, ?, ?, 'member', ?)`,\n args: [nanoid(), m.orgId, email, Date.now()],\n });\n joined.push({ orgId: m.orgId });\n } catch {\n // Race with a parallel join (e.g. user accepted an invite to the\n // same org milliseconds earlier). The unique constraint keeps the\n // existing membership intact; just skip this org.\n }\n }\n\n // Set active-org-id to the first match only if the user doesn't\n // already have one (a pending invite that ran first may have set it).\n let activeOrgId: string | null = null;\n if (joined[0]) {\n try {\n const existing = await getUserSetting(email, \"active-org-id\");\n const hasActive = Boolean(existing?.orgId);\n if (!hasActive) {\n activeOrgId = joined[0].orgId;\n await putUserSetting(email, \"active-org-id\", { orgId: activeOrgId });\n }\n } catch {\n // settings table missing — not fatal.\n }\n }\n\n return { joined, activeOrgId };\n}\n"]}
|
package/dist/org/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export type { OrgRole, OrgContext, OrgSummary, OrgInvitationSummary, OrgInfo, Or
|
|
|
2
2
|
export { getOrgContext, getOrgDomain, getOrgA2ASecret, getA2ASecretByDomain, resolveOrgByDomain, resolveOrgIdForEmail, } from "./context.js";
|
|
3
3
|
export { acceptPendingInvitationsForEmail } from "./accept-pending.js";
|
|
4
4
|
export type { AcceptPendingResult } from "./accept-pending.js";
|
|
5
|
+
export { autoJoinDomainMatchingOrgs } from "./auto-join-domain.js";
|
|
6
|
+
export type { AutoJoinDomainResult } from "./auto-join-domain.js";
|
|
5
7
|
export { ORG_MIGRATIONS } from "./migrations.js";
|
|
6
8
|
export { createOrgPlugin, defaultOrgPlugin } from "./plugin.js";
|
|
7
9
|
export { organizations, orgMembers, orgInvitations } from "./schema.js";
|
package/dist/org/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/org/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,OAAO,EACP,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIhE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIxE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/org/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,OAAO,EACP,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIhE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIxE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC"}
|
package/dist/org/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Public API for the org module.
|
|
2
2
|
export { getOrgContext, getOrgDomain, getOrgA2ASecret, getA2ASecretByDomain, resolveOrgByDomain, resolveOrgIdForEmail, } from "./context.js";
|
|
3
3
|
export { acceptPendingInvitationsForEmail } from "./accept-pending.js";
|
|
4
|
+
export { autoJoinDomainMatchingOrgs } from "./auto-join-domain.js";
|
|
4
5
|
export { ORG_MIGRATIONS } from "./migrations.js";
|
|
5
6
|
export { createOrgPlugin, defaultOrgPlugin } from "./plugin.js";
|
|
6
7
|
// Drizzle schema (re-exported so templates can write typed queries against
|
package/dist/org/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/org/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAYjC,OAAO,EACL,aAAa,EACb,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEhE,2EAA2E;AAC3E,wDAAwD;AACxD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAExE,8EAA8E;AAC9E,qDAAqD;AACrD,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC","sourcesContent":["// Public API for the org module.\n\nexport type {\n OrgRole,\n OrgContext,\n OrgSummary,\n OrgInvitationSummary,\n OrgInfo,\n OrgMember,\n OrgPendingInvitation,\n} from \"./types.js\";\n\nexport {\n getOrgContext,\n getOrgDomain,\n getOrgA2ASecret,\n getA2ASecretByDomain,\n resolveOrgByDomain,\n resolveOrgIdForEmail,\n} from \"./context.js\";\n\nexport { acceptPendingInvitationsForEmail } from \"./accept-pending.js\";\nexport type { AcceptPendingResult } from \"./accept-pending.js\";\n\nexport { ORG_MIGRATIONS } from \"./migrations.js\";\n\nexport { createOrgPlugin, defaultOrgPlugin } from \"./plugin.js\";\n\n// Drizzle schema (re-exported so templates can write typed queries against\n// org tables without redefining the schema themselves).\nexport { organizations, orgMembers, orgInvitations } from \"./schema.js\";\n\n// Individual handlers — exported so templates can compose a custom org plugin\n// while still using the framework-provided handlers.\nexport {\n getMyOrgHandler,\n createOrgHandler,\n updateOrgHandler,\n switchOrgHandler,\n listMembersHandler,\n removeMemberHandler,\n listInvitationsHandler,\n createInvitationHandler,\n acceptInvitationHandler,\n setA2ASecretHandler,\n syncA2ASecretHandler,\n receiveA2ASecretHandler,\n} from \"./handlers.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/org/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAYjC,OAAO,EACL,aAAa,EACb,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AAGvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAGnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEhE,2EAA2E;AAC3E,wDAAwD;AACxD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAExE,8EAA8E;AAC9E,qDAAqD;AACrD,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC","sourcesContent":["// Public API for the org module.\n\nexport type {\n OrgRole,\n OrgContext,\n OrgSummary,\n OrgInvitationSummary,\n OrgInfo,\n OrgMember,\n OrgPendingInvitation,\n} from \"./types.js\";\n\nexport {\n getOrgContext,\n getOrgDomain,\n getOrgA2ASecret,\n getA2ASecretByDomain,\n resolveOrgByDomain,\n resolveOrgIdForEmail,\n} from \"./context.js\";\n\nexport { acceptPendingInvitationsForEmail } from \"./accept-pending.js\";\nexport type { AcceptPendingResult } from \"./accept-pending.js\";\n\nexport { autoJoinDomainMatchingOrgs } from \"./auto-join-domain.js\";\nexport type { AutoJoinDomainResult } from \"./auto-join-domain.js\";\n\nexport { ORG_MIGRATIONS } from \"./migrations.js\";\n\nexport { createOrgPlugin, defaultOrgPlugin } from \"./plugin.js\";\n\n// Drizzle schema (re-exported so templates can write typed queries against\n// org tables without redefining the schema themselves).\nexport { organizations, orgMembers, orgInvitations } from \"./schema.js\";\n\n// Individual handlers — exported so templates can compose a custom org plugin\n// while still using the framework-provided handlers.\nexport {\n getMyOrgHandler,\n createOrgHandler,\n updateOrgHandler,\n switchOrgHandler,\n listMembersHandler,\n removeMemberHandler,\n listInvitationsHandler,\n createInvitationHandler,\n acceptInvitationHandler,\n setA2ASecretHandler,\n syncA2ASecretHandler,\n receiveA2ASecretHandler,\n} from \"./handlers.js\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAqkBH,wBAA8B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4JlE"}
|
package/dist/scripts/db/exec.js
CHANGED
|
@@ -388,7 +388,29 @@ function printResult(sql, result, hasReturning, format) {
|
|
|
388
388
|
if (result.lastInsertRowid && changes > 0) {
|
|
389
389
|
console.log(`Last Insert Row ID: ${result.lastInsertRowid}`);
|
|
390
390
|
}
|
|
391
|
+
if (changes === 0) {
|
|
392
|
+
console.log(zeroChangesHint(sql));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Hint emitted when an UPDATE/DELETE/REPLACE matches zero rows. Matches the
|
|
398
|
+
* wording used by db-patch's "no rows matched" error so the agent gets the
|
|
399
|
+
* same scoping nudge from both tools — without this hint, the agent reports
|
|
400
|
+
* "Changes: 0" as success and the user sees no UI update because the row
|
|
401
|
+
* either didn't exist or wasn't visible to the current user under per-user
|
|
402
|
+
* scoping.
|
|
403
|
+
*/
|
|
404
|
+
function zeroChangesHint(sql) {
|
|
405
|
+
const upper = sql.toUpperCase(); // leading whitespace already stripped by normalizeUserSql
|
|
406
|
+
if (upper.startsWith("INSERT")) {
|
|
407
|
+
// INSERT changes=0 means INSERT OR IGNORE skipped a duplicate — different
|
|
408
|
+
// failure mode, not a scoping issue.
|
|
409
|
+
return "Hint: 0 rows inserted. The row likely violated a UNIQUE / PRIMARY KEY constraint and was skipped (INSERT OR IGNORE).";
|
|
391
410
|
}
|
|
411
|
+
return ("Hint: 0 rows changed. The WHERE clause matched no rows — either the row " +
|
|
412
|
+
"doesn't exist, or it exists but is owned by a different user (per-user " +
|
|
413
|
+
"and per-org scoping is automatic for db-exec).");
|
|
392
414
|
}
|
|
393
415
|
function printBatchResult(results, format) {
|
|
394
416
|
if (results.length === 1) {
|
|
@@ -426,7 +448,11 @@ function printBatchResult(results, format) {
|
|
|
426
448
|
console.log(JSON.stringify(result.rows, null, 2));
|
|
427
449
|
}
|
|
428
450
|
else {
|
|
429
|
-
|
|
451
|
+
const changes = Number(result.changes ?? 0);
|
|
452
|
+
console.log(`[${result.index}] Changes: ${changes}`);
|
|
453
|
+
if (changes === 0) {
|
|
454
|
+
console.log(`[${result.index}] ${zeroChangesHint(result.sql)}`);
|
|
455
|
+
}
|
|
430
456
|
}
|
|
431
457
|
}
|
|
432
458
|
console.log(`Total changes: ${totalChanges}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Core script: db-exec\n *\n * Execute write SQL statements (INSERT, UPDATE, DELETE, REPLACE)\n * against a SQLite or Postgres database.\n *\n * In production mode, temporary views scope UPDATE/DELETE to the current\n * user's data (AGENT_USER_EMAIL / AGENT_ORG_ID). For INSERT, the\n * `owner_email` and `org_id` columns are auto-injected if the target\n * table uses the ownership convention.\n *\n * Usage:\n * pnpm action db-exec --sql \"UPDATE forms SET status=? WHERE id=?\" [--args '[\"published\",\"abc\"]'] [--db path]\n * pnpm action db-exec --statements '[{\"sql\":\"INSERT INTO notes (id,title) VALUES (?,?)\",\"args\":[\"n1\",\"One\"]},{\"sql\":\"UPDATE counters SET value=value+1 WHERE key=?\",\"args\":[\"notes\"]}]'\n */\n\nimport path from \"path\";\nimport { createClient } from \"@libsql/client\";\nimport { getDatabaseUrl, getDatabaseAuthToken } from \"../../db/client.js\";\nimport { parseArgs, fail } from \"../utils.js\";\nimport {\n buildScopingPostgres,\n buildScopingSqlite,\n type ScopingContext,\n} from \"./scoping.js\";\nimport { assertNoSensitiveFrameworkTables } from \"./safety.js\";\n\nfunction isPostgresUrl(url: string): boolean {\n return url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\");\n}\n\ninterface DbExecStatement {\n sql: string;\n args: unknown[];\n}\n\ninterface DbExecResult {\n index: number;\n sql: string;\n changes?: number;\n lastInsertRowid?: bigint | number;\n rows?: Record<string, unknown>[];\n}\n\nfunction parseSqlArgs(raw: string | undefined, label = \"--args\"): unknown[] {\n if (!raw) return [];\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) return parsed;\n } catch {\n // Fall through to the shared error below.\n }\n fail(`${label} must be a JSON array`);\n}\n\nfunction parseStatements(parsed: Record<string, string>): DbExecStatement[] {\n if (parsed.statements) {\n if (parsed.sql) {\n fail(\"Pass either --sql or --statements, not both.\");\n }\n let raw: unknown;\n try {\n raw = JSON.parse(parsed.statements);\n } catch {\n fail(\n '--statements must be a JSON array of {\"sql\": string, \"args\"?: unknown[]} objects',\n );\n }\n if (!Array.isArray(raw) || raw.length === 0) {\n fail(\"--statements must be a non-empty JSON array\");\n }\n return raw.map((entry, index) => {\n if (\n !entry ||\n typeof entry !== \"object\" ||\n typeof (entry as any).sql !== \"string\" ||\n !(entry as any).sql.trim()\n ) {\n fail(`Statement ${index + 1} must include a non-empty sql string`);\n }\n const args = (entry as any).args;\n if (args != null && !Array.isArray(args)) {\n fail(`Statement ${index + 1} args must be a JSON array`);\n }\n return { sql: (entry as any).sql, args: args ?? [] };\n });\n }\n\n if (!parsed.sql) {\n fail(\n '--sql is required unless --statements is provided. Example: --sql \"UPDATE forms SET status=? WHERE id=?\" --args \\'[\"published\",\"abc\"]\\'',\n );\n }\n return [{ sql: parsed.sql, args: parseSqlArgs(parsed.args) }];\n}\n\nfunction stripLeadingSqlComments(sql: string): string {\n return sql\n .replace(/^\\s*--[^\\n]*\\n/gm, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .trim();\n}\n\nfunction hasAdditionalStatement(sql: string): boolean {\n let state: \"normal\" | \"single\" | \"double\" | \"line-comment\" | \"block-comment\" =\n \"normal\";\n\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i];\n const next = sql[i + 1];\n\n if (state === \"line-comment\") {\n if (ch === \"\\n\") state = \"normal\";\n continue;\n }\n if (state === \"block-comment\") {\n if (ch === \"*\" && next === \"/\") {\n i++;\n state = \"normal\";\n }\n continue;\n }\n if (state === \"single\") {\n if (ch === \"'\" && next === \"'\") {\n i++;\n } else if (ch === \"'\") {\n state = \"normal\";\n }\n continue;\n }\n if (state === \"double\") {\n if (ch === '\"' && next === '\"') {\n i++;\n } else if (ch === '\"') {\n state = \"normal\";\n }\n continue;\n }\n\n if (ch === \"-\" && next === \"-\") {\n i++;\n state = \"line-comment\";\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n i++;\n state = \"block-comment\";\n continue;\n }\n if (ch === \"'\") {\n state = \"single\";\n continue;\n }\n if (ch === '\"') {\n state = \"double\";\n continue;\n }\n if (ch === \";\") {\n return sql.slice(i + 1).trim().length > 0;\n }\n }\n return false;\n}\n\nfunction normalizeUserSql(sql: string, index: number): string {\n const stripped = stripLeadingSqlComments(sql);\n if (!stripped) {\n fail(`Statement ${index} is empty`);\n }\n if (hasAdditionalStatement(stripped)) {\n fail(\n `Statement ${index} contains multiple SQL statements. Use --statements for batches so each write can be validated and run transactionally.`,\n );\n }\n return stripped.replace(/;\\s*$/, \"\");\n}\n\nfunction validateWriteSql(sql: string, index: number): string {\n const normalized = normalizeUserSql(sql, index);\n const upper = normalized.toUpperCase();\n const allowed = [\"INSERT\", \"UPDATE\", \"DELETE\", \"REPLACE\"];\n const blocked = [\"SELECT\", \"WITH\", \"EXPLAIN\", \"PRAGMA\"];\n\n if (blocked.some((kw) => upper.startsWith(kw))) {\n fail(\n `Statement ${index}: use db-query for SELECT/read statements. db-exec is for writes only.`,\n );\n }\n if (upper.startsWith(\"CREATE\") || upper.startsWith(\"ALTER\")) {\n fail(\n `Statement ${index}: schema changes are not allowed through db-exec. Additive schema changes must go through reviewed migrations/startup code, not ad-hoc agent SQL.`,\n );\n }\n if (!allowed.some((kw) => upper.startsWith(kw))) {\n fail(\n `Statement ${index}: only ${allowed.join(\", \")} statements are allowed. ` +\n `Dangerous operations like DROP, ATTACH, VACUUM, DETACH, CREATE, and ALTER are blocked.`,\n );\n }\n assertNoSensitiveFrameworkTables(normalized, \"write\");\n return normalized;\n}\n\nfunction convertQuestionMarksToPostgresParams(sql: string): string {\n let index = 0;\n let out = \"\";\n let state: \"normal\" | \"single\" | \"double\" | \"line-comment\" | \"block-comment\" =\n \"normal\";\n\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i];\n const next = sql[i + 1];\n\n if (state === \"line-comment\") {\n out += ch;\n if (ch === \"\\n\") state = \"normal\";\n continue;\n }\n\n if (state === \"block-comment\") {\n out += ch;\n if (ch === \"*\" && next === \"/\") {\n out += next;\n i++;\n state = \"normal\";\n }\n continue;\n }\n\n if (state === \"single\") {\n out += ch;\n if (ch === \"'\" && next === \"'\") {\n out += next;\n i++;\n } else if (ch === \"'\") {\n state = \"normal\";\n }\n continue;\n }\n\n if (state === \"double\") {\n out += ch;\n if (ch === '\"' && next === '\"') {\n out += next;\n i++;\n } else if (ch === '\"') {\n state = \"normal\";\n }\n continue;\n }\n\n if (ch === \"-\" && next === \"-\") {\n out += ch + next;\n i++;\n state = \"line-comment\";\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n out += ch + next;\n i++;\n state = \"block-comment\";\n continue;\n }\n if (ch === \"'\") {\n out += ch;\n state = \"single\";\n continue;\n }\n if (ch === '\"') {\n out += ch;\n state = \"double\";\n continue;\n }\n if (ch === \"?\") {\n index++;\n out += `$${index}`;\n continue;\n }\n out += ch;\n }\n\n return out;\n}\n\nfunction normalizePostgresSql(sql: string, args: unknown[]): string {\n if (args.length === 0 || /\\$\\d+\\b/.test(sql)) return sql;\n return convertQuestionMarksToPostgresParams(sql);\n}\n\n/**\n * For INSERT statements targeting a table with owner_email / org_id columns,\n * auto-inject the current user's email and org ID if not already present.\n *\n * Handles the explicit column list form:\n * INSERT INTO table (col1, col2) VALUES (val1, val2)\n */\nfunction injectOwnership(sql: string, scoping: ScopingContext): string {\n if (!scoping.active) return sql;\n\n const upper = sql\n .replace(/^\\s*--[^\\n]*\\n/gm, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .trim()\n .toUpperCase();\n if (!upper.startsWith(\"INSERT\")) return sql;\n\n // Extract table name: INSERT INTO <table> ...\n const match = sql.match(/INSERT\\s+INTO\\s+[\"']?(\\w+)[\"']?/i);\n if (!match) return sql;\n\n const tableName = match[1];\n\n // Determine which columns to inject\n const injections: { col: string; value: string }[] = [];\n\n if (\n scoping.userEmail &&\n scoping.ownerEmailTables.has(tableName) &&\n !/owner_email/i.test(sql)\n ) {\n injections.push({\n col: \"owner_email\",\n value: `'${scoping.userEmail.replace(/'/g, \"''\")}'`,\n });\n }\n\n if (\n scoping.orgId &&\n scoping.orgIdTables.has(tableName) &&\n !/org_id/i.test(sql)\n ) {\n injections.push({\n col: \"org_id\",\n value: `'${scoping.orgId.replace(/'/g, \"''\")}'`,\n });\n }\n\n if (injections.length === 0) return sql;\n\n // Try to inject into explicit column list: INSERT INTO t (cols) VALUES (vals)\n const colListMatch = sql.match(\n /(INSERT\\s+INTO\\s+[\"']?\\w+[\"']?\\s*)\\(([^)]+)\\)(\\s*VALUES\\s*)\\(([^)]+)\\)/i,\n );\n if (colListMatch) {\n const [, prefix, cols, valueKeyword, vals] = colListMatch;\n const extraCols = injections.map((i) => i.col).join(\", \");\n const extraVals = injections.map((i) => i.value).join(\", \");\n return `${prefix}(${cols}, ${extraCols})${valueKeyword}(${vals}, ${extraVals})`;\n }\n\n return sql;\n}\n\nfunction escapeSqlString(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\nfunction sqliteScopePredicate(\n tableName: string,\n scoping: ScopingContext,\n): string | null {\n if (tableName === \"tool_data\" && scoping.userEmail) {\n const userClause = `(scope = 'user' AND owner_email = '${escapeSqlString(scoping.userEmail)}')`;\n const orgClause = scoping.orgId\n ? ` OR (scope = 'org' AND org_id = '${escapeSqlString(scoping.orgId)}')`\n : \"\";\n return `(${userClause}${orgClause})`;\n }\n\n const clauses: string[] = [];\n if (scoping.userEmail && scoping.ownerEmailTables.has(tableName)) {\n clauses.push(`owner_email = '${escapeSqlString(scoping.userEmail)}'`);\n }\n if (scoping.orgId && scoping.orgIdTables.has(tableName)) {\n clauses.push(`org_id = '${escapeSqlString(scoping.orgId)}'`);\n }\n return clauses.length > 0 ? clauses.join(\" AND \") : null;\n}\n\nfunction splitReturning(sql: string): { body: string; returning: string } {\n const match = /\\bRETURNING\\b/i.exec(sql);\n if (!match) return { body: sql, returning: \"\" };\n return {\n body: sql.slice(0, match.index).trimEnd(),\n returning: sql.slice(match.index),\n };\n}\n\nfunction addSqliteScopeToWhere(sql: string, predicate: string): string {\n const { body, returning } = splitReturning(sql);\n const whereMatch = /\\bWHERE\\b/i.exec(body);\n const scoped = whereMatch\n ? `${body.slice(0, whereMatch.index)}WHERE ${predicate} AND (${body.slice(whereMatch.index + whereMatch[0].length).trim()})`\n : `${body} WHERE ${predicate}`;\n return returning ? `${scoped} ${returning}` : scoped;\n}\n\nfunction qualifySqliteWrite(sql: string, scoping: ScopingContext): string {\n if (!scoping.active) return sql;\n\n const updateMatch = sql.match(/^\\s*UPDATE\\s+(?:\"([^\"]+)\"|'([^']+)'|(\\w+))/i);\n if (updateMatch) {\n const tableName = updateMatch[1] ?? updateMatch[2] ?? updateMatch[3];\n const predicate = sqliteScopePredicate(tableName, scoping);\n if (!predicate) return sql;\n const qualified = sql.replace(\n /^\\s*UPDATE\\s+(?:\"[^\"]+\"|'[^']+'|\\w+)/i,\n `UPDATE main.\"${tableName.replace(/\"/g, '\"\"')}\"`,\n );\n return addSqliteScopeToWhere(qualified, predicate);\n }\n\n const deleteMatch = sql.match(\n /^\\s*DELETE\\s+FROM\\s+(?:\"([^\"]+)\"|'([^']+)'|(\\w+))/i,\n );\n if (deleteMatch) {\n const tableName = deleteMatch[1] ?? deleteMatch[2] ?? deleteMatch[3];\n const predicate = sqliteScopePredicate(tableName, scoping);\n if (!predicate) return sql;\n const qualified = sql.replace(\n /^\\s*DELETE\\s+FROM\\s+(?:\"[^\"]+\"|'[^']+'|\\w+)/i,\n `DELETE FROM main.\"${tableName.replace(/\"/g, '\"\"')}\"`,\n );\n return addSqliteScopeToWhere(qualified, predicate);\n }\n\n return sql.replace(\n /^\\s*(INSERT\\s+INTO|REPLACE\\s+INTO)\\s+(?:\"([^\"]+)\"|'([^']+)'|(\\w+))/i,\n (match, keyword, quotedDouble, quotedSingle, bare) => {\n const tableName = quotedDouble ?? quotedSingle ?? bare;\n if (\n !scoping.ownerEmailTables.has(tableName) &&\n !scoping.orgIdTables.has(tableName)\n ) {\n return match;\n }\n return `${keyword} main.\"${tableName.replace(/\"/g, '\"\"')}\"`;\n },\n );\n}\n\nfunction printResult(\n sql: string,\n result: {\n count?: number;\n rowsAffected?: number;\n lastInsertRowid?: bigint | number;\n rows?: Record<string, unknown>[];\n },\n hasReturning: boolean,\n format?: string,\n) {\n if (hasReturning && result.rows && result.rows.length > 0) {\n if (format === \"json\") {\n console.log(\n JSON.stringify(\n { sql, rows: result.rows, count: result.rows.length },\n null,\n 2,\n ),\n );\n return;\n }\n console.log(`Executed: ${sql}`);\n console.log(`Returned ${result.rows.length} row(s):`);\n console.log(JSON.stringify(result.rows, null, 2));\n } else {\n const changes = result.count ?? result.rowsAffected ?? 0;\n if (format === \"json\") {\n console.log(\n JSON.stringify(\n {\n sql,\n changes,\n ...(result.lastInsertRowid && changes > 0\n ? { lastInsertRowid: Number(result.lastInsertRowid) }\n : {}),\n },\n null,\n 2,\n ),\n );\n return;\n }\n console.log(`Executed: ${sql}`);\n console.log(`Changes: ${changes}`);\n if (result.lastInsertRowid && changes > 0) {\n console.log(`Last Insert Row ID: ${result.lastInsertRowid}`);\n }\n }\n}\n\nfunction printBatchResult(results: DbExecResult[], format?: string): void {\n if (results.length === 1) {\n const result = results[0];\n printResult(\n result.sql,\n {\n count: result.changes,\n rowsAffected: result.changes,\n lastInsertRowid: result.lastInsertRowid,\n rows: result.rows,\n },\n Boolean(result.rows?.length),\n format,\n );\n return;\n }\n\n const totalChanges = results.reduce(\n (sum, result) => sum + Number(result.changes ?? 0),\n 0,\n );\n\n if (format === \"json\") {\n console.log(\n JSON.stringify(\n {\n statements: results.map((result) => ({\n index: result.index,\n sql: result.sql,\n changes: result.changes ?? 0,\n ...(result.lastInsertRowid && Number(result.changes ?? 0) > 0\n ? { lastInsertRowid: Number(result.lastInsertRowid) }\n : {}),\n ...(result.rows?.length\n ? { rows: result.rows, count: result.rows.length }\n : {}),\n })),\n changes: totalChanges,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(`Executed ${results.length} statements in one transaction.`);\n for (const result of results) {\n if (result.rows?.length) {\n console.log(`[${result.index}] Returned ${result.rows.length} row(s):`);\n console.log(JSON.stringify(result.rows, null, 2));\n } else {\n console.log(`[${result.index}] Changes: ${result.changes ?? 0}`);\n }\n }\n console.log(`Total changes: ${totalChanges}`);\n}\n\nfunction sqliteRowsToObjects(\n rows: any[],\n columns: string[],\n): Record<string, unknown>[] {\n return rows.map((row) => {\n if (!Array.isArray(row) && row && typeof row === \"object\") {\n return { ...row };\n }\n const obj: Record<string, unknown> = {};\n for (let i = 0; i < columns.length; i++) {\n obj[columns[i]] = row[i];\n }\n return obj;\n });\n}\n\nexport default async function dbExec(args: string[]): Promise<void> {\n const parsed = parseArgs(args);\n\n if (parsed.help === \"true\") {\n console.log(`Usage: pnpm action db-exec --sql \"<statement>\" [options]\n pnpm action db-exec --statements '[{\"sql\":\"UPDATE ...\",\"args\":[...]}]' [options]\n\nOptions:\n --sql <stmt> Single INSERT / UPDATE / DELETE / REPLACE statement\n --args <json> JSON array of positional SQL bind parameters for --sql\n --statements <json> JSON array of {sql, args?}; runs in one transaction\n --db <path> Path to SQLite database (default: data/app.db)\n --format json Output as JSON\n --help Show this help message`);\n return;\n }\n\n const statements = parseStatements(parsed).map((statement, index) => ({\n sql: validateWriteSql(statement.sql, index + 1),\n args: statement.args,\n }));\n\n // Resolve database URL: --db flag → DATABASE_URL env → default file path\n let url: string;\n if (parsed.db) {\n url = \"file:\" + path.resolve(parsed.db);\n } else if (getDatabaseUrl()) {\n url = getDatabaseUrl();\n } else {\n url = \"file:\" + path.resolve(process.cwd(), \"data\", \"app.db\");\n }\n\n // Postgres path\n if (isPostgresUrl(url)) {\n const { default: pg } = await import(\"postgres\");\n const pgSql = pg(url);\n try {\n // Set up user-scoped temp views in production\n const scoping = await buildScopingPostgres(pgSql);\n\n const results: DbExecResult[] = [];\n await pgSql.begin(async (tx: any) => {\n try {\n // For UPDATE/DELETE: temp views scope to current user's rows.\n // Creating and dropping them inside the same transaction keeps\n // pooled Postgres backends from retaining session-local views.\n for (const stmt of scoping.setup) {\n await tx.unsafe(stmt);\n }\n\n for (let i = 0; i < statements.length; i++) {\n const statement = statements[i];\n const hasReturning = /\\bRETURNING\\b/i.test(statement.sql);\n const finalSql = normalizePostgresSql(\n injectOwnership(statement.sql, scoping),\n statement.args,\n );\n try {\n const result =\n statement.args.length > 0\n ? await tx.unsafe(finalSql, statement.args as any[])\n : await tx.unsafe(finalSql);\n const rows: Record<string, unknown>[] =\n hasReturning && result.length > 0 ? Array.from(result) : [];\n results.push({\n index: i + 1,\n sql: finalSql,\n changes: result.count ?? 0,\n rows,\n });\n } catch (err: any) {\n throw new Error(\n `Statement ${i + 1} failed: ${err?.message ?? String(err)}`,\n );\n }\n }\n } finally {\n for (const stmt of scoping.teardown) {\n await tx.unsafe(stmt).catch(() => {});\n }\n }\n });\n\n printBatchResult(results, parsed.format);\n } finally {\n await pgSql.end();\n }\n return;\n }\n\n // libsql / SQLite path\n const client = createClient({\n url,\n authToken: getDatabaseAuthToken(),\n });\n\n try {\n // Set up user-scoped temp views in production\n const scoping = await buildScopingSqlite(client);\n for (const stmt of scoping.setup) {\n await client.execute(stmt);\n }\n\n const results: DbExecResult[] = [];\n const shouldTransact = statements.length > 1;\n if (shouldTransact) await client.execute(\"BEGIN\");\n try {\n for (let i = 0; i < statements.length; i++) {\n const statement = statements[i];\n const hasReturning = /\\bRETURNING\\b/i.test(statement.sql);\n const finalSql = qualifySqliteWrite(\n injectOwnership(statement.sql, scoping),\n scoping,\n );\n try {\n const result =\n statement.args.length > 0\n ? await client.execute({\n sql: finalSql,\n args: statement.args as any[],\n })\n : await client.execute(finalSql);\n\n const rows: Record<string, unknown>[] =\n hasReturning && result.rows.length > 0\n ? sqliteRowsToObjects(result.rows, result.columns)\n : [];\n results.push({\n index: i + 1,\n sql: finalSql,\n changes: result.rowsAffected,\n lastInsertRowid: result.lastInsertRowid,\n rows,\n });\n } catch (err: any) {\n throw new Error(\n `Statement ${i + 1} failed: ${err?.message ?? String(err)}`,\n );\n }\n }\n if (shouldTransact) await client.execute(\"COMMIT\");\n } catch (err) {\n if (shouldTransact) {\n await client.execute(\"ROLLBACK\").catch(() => {});\n }\n throw err;\n }\n\n printBatchResult(results, parsed.format);\n\n for (const stmt of scoping.teardown) {\n await client.execute(stmt).catch(() => {});\n }\n } finally {\n client.close();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Core script: db-exec\n *\n * Execute write SQL statements (INSERT, UPDATE, DELETE, REPLACE)\n * against a SQLite or Postgres database.\n *\n * In production mode, temporary views scope UPDATE/DELETE to the current\n * user's data (AGENT_USER_EMAIL / AGENT_ORG_ID). For INSERT, the\n * `owner_email` and `org_id` columns are auto-injected if the target\n * table uses the ownership convention.\n *\n * Usage:\n * pnpm action db-exec --sql \"UPDATE forms SET status=? WHERE id=?\" [--args '[\"published\",\"abc\"]'] [--db path]\n * pnpm action db-exec --statements '[{\"sql\":\"INSERT INTO notes (id,title) VALUES (?,?)\",\"args\":[\"n1\",\"One\"]},{\"sql\":\"UPDATE counters SET value=value+1 WHERE key=?\",\"args\":[\"notes\"]}]'\n */\n\nimport path from \"path\";\nimport { createClient } from \"@libsql/client\";\nimport { getDatabaseUrl, getDatabaseAuthToken } from \"../../db/client.js\";\nimport { parseArgs, fail } from \"../utils.js\";\nimport {\n buildScopingPostgres,\n buildScopingSqlite,\n type ScopingContext,\n} from \"./scoping.js\";\nimport { assertNoSensitiveFrameworkTables } from \"./safety.js\";\n\nfunction isPostgresUrl(url: string): boolean {\n return url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\");\n}\n\ninterface DbExecStatement {\n sql: string;\n args: unknown[];\n}\n\ninterface DbExecResult {\n index: number;\n sql: string;\n changes?: number;\n lastInsertRowid?: bigint | number;\n rows?: Record<string, unknown>[];\n}\n\nfunction parseSqlArgs(raw: string | undefined, label = \"--args\"): unknown[] {\n if (!raw) return [];\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) return parsed;\n } catch {\n // Fall through to the shared error below.\n }\n fail(`${label} must be a JSON array`);\n}\n\nfunction parseStatements(parsed: Record<string, string>): DbExecStatement[] {\n if (parsed.statements) {\n if (parsed.sql) {\n fail(\"Pass either --sql or --statements, not both.\");\n }\n let raw: unknown;\n try {\n raw = JSON.parse(parsed.statements);\n } catch {\n fail(\n '--statements must be a JSON array of {\"sql\": string, \"args\"?: unknown[]} objects',\n );\n }\n if (!Array.isArray(raw) || raw.length === 0) {\n fail(\"--statements must be a non-empty JSON array\");\n }\n return raw.map((entry, index) => {\n if (\n !entry ||\n typeof entry !== \"object\" ||\n typeof (entry as any).sql !== \"string\" ||\n !(entry as any).sql.trim()\n ) {\n fail(`Statement ${index + 1} must include a non-empty sql string`);\n }\n const args = (entry as any).args;\n if (args != null && !Array.isArray(args)) {\n fail(`Statement ${index + 1} args must be a JSON array`);\n }\n return { sql: (entry as any).sql, args: args ?? [] };\n });\n }\n\n if (!parsed.sql) {\n fail(\n '--sql is required unless --statements is provided. Example: --sql \"UPDATE forms SET status=? WHERE id=?\" --args \\'[\"published\",\"abc\"]\\'',\n );\n }\n return [{ sql: parsed.sql, args: parseSqlArgs(parsed.args) }];\n}\n\nfunction stripLeadingSqlComments(sql: string): string {\n return sql\n .replace(/^\\s*--[^\\n]*\\n/gm, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .trim();\n}\n\nfunction hasAdditionalStatement(sql: string): boolean {\n let state: \"normal\" | \"single\" | \"double\" | \"line-comment\" | \"block-comment\" =\n \"normal\";\n\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i];\n const next = sql[i + 1];\n\n if (state === \"line-comment\") {\n if (ch === \"\\n\") state = \"normal\";\n continue;\n }\n if (state === \"block-comment\") {\n if (ch === \"*\" && next === \"/\") {\n i++;\n state = \"normal\";\n }\n continue;\n }\n if (state === \"single\") {\n if (ch === \"'\" && next === \"'\") {\n i++;\n } else if (ch === \"'\") {\n state = \"normal\";\n }\n continue;\n }\n if (state === \"double\") {\n if (ch === '\"' && next === '\"') {\n i++;\n } else if (ch === '\"') {\n state = \"normal\";\n }\n continue;\n }\n\n if (ch === \"-\" && next === \"-\") {\n i++;\n state = \"line-comment\";\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n i++;\n state = \"block-comment\";\n continue;\n }\n if (ch === \"'\") {\n state = \"single\";\n continue;\n }\n if (ch === '\"') {\n state = \"double\";\n continue;\n }\n if (ch === \";\") {\n return sql.slice(i + 1).trim().length > 0;\n }\n }\n return false;\n}\n\nfunction normalizeUserSql(sql: string, index: number): string {\n const stripped = stripLeadingSqlComments(sql);\n if (!stripped) {\n fail(`Statement ${index} is empty`);\n }\n if (hasAdditionalStatement(stripped)) {\n fail(\n `Statement ${index} contains multiple SQL statements. Use --statements for batches so each write can be validated and run transactionally.`,\n );\n }\n return stripped.replace(/;\\s*$/, \"\");\n}\n\nfunction validateWriteSql(sql: string, index: number): string {\n const normalized = normalizeUserSql(sql, index);\n const upper = normalized.toUpperCase();\n const allowed = [\"INSERT\", \"UPDATE\", \"DELETE\", \"REPLACE\"];\n const blocked = [\"SELECT\", \"WITH\", \"EXPLAIN\", \"PRAGMA\"];\n\n if (blocked.some((kw) => upper.startsWith(kw))) {\n fail(\n `Statement ${index}: use db-query for SELECT/read statements. db-exec is for writes only.`,\n );\n }\n if (upper.startsWith(\"CREATE\") || upper.startsWith(\"ALTER\")) {\n fail(\n `Statement ${index}: schema changes are not allowed through db-exec. Additive schema changes must go through reviewed migrations/startup code, not ad-hoc agent SQL.`,\n );\n }\n if (!allowed.some((kw) => upper.startsWith(kw))) {\n fail(\n `Statement ${index}: only ${allowed.join(\", \")} statements are allowed. ` +\n `Dangerous operations like DROP, ATTACH, VACUUM, DETACH, CREATE, and ALTER are blocked.`,\n );\n }\n assertNoSensitiveFrameworkTables(normalized, \"write\");\n return normalized;\n}\n\nfunction convertQuestionMarksToPostgresParams(sql: string): string {\n let index = 0;\n let out = \"\";\n let state: \"normal\" | \"single\" | \"double\" | \"line-comment\" | \"block-comment\" =\n \"normal\";\n\n for (let i = 0; i < sql.length; i++) {\n const ch = sql[i];\n const next = sql[i + 1];\n\n if (state === \"line-comment\") {\n out += ch;\n if (ch === \"\\n\") state = \"normal\";\n continue;\n }\n\n if (state === \"block-comment\") {\n out += ch;\n if (ch === \"*\" && next === \"/\") {\n out += next;\n i++;\n state = \"normal\";\n }\n continue;\n }\n\n if (state === \"single\") {\n out += ch;\n if (ch === \"'\" && next === \"'\") {\n out += next;\n i++;\n } else if (ch === \"'\") {\n state = \"normal\";\n }\n continue;\n }\n\n if (state === \"double\") {\n out += ch;\n if (ch === '\"' && next === '\"') {\n out += next;\n i++;\n } else if (ch === '\"') {\n state = \"normal\";\n }\n continue;\n }\n\n if (ch === \"-\" && next === \"-\") {\n out += ch + next;\n i++;\n state = \"line-comment\";\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n out += ch + next;\n i++;\n state = \"block-comment\";\n continue;\n }\n if (ch === \"'\") {\n out += ch;\n state = \"single\";\n continue;\n }\n if (ch === '\"') {\n out += ch;\n state = \"double\";\n continue;\n }\n if (ch === \"?\") {\n index++;\n out += `$${index}`;\n continue;\n }\n out += ch;\n }\n\n return out;\n}\n\nfunction normalizePostgresSql(sql: string, args: unknown[]): string {\n if (args.length === 0 || /\\$\\d+\\b/.test(sql)) return sql;\n return convertQuestionMarksToPostgresParams(sql);\n}\n\n/**\n * For INSERT statements targeting a table with owner_email / org_id columns,\n * auto-inject the current user's email and org ID if not already present.\n *\n * Handles the explicit column list form:\n * INSERT INTO table (col1, col2) VALUES (val1, val2)\n */\nfunction injectOwnership(sql: string, scoping: ScopingContext): string {\n if (!scoping.active) return sql;\n\n const upper = sql\n .replace(/^\\s*--[^\\n]*\\n/gm, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .trim()\n .toUpperCase();\n if (!upper.startsWith(\"INSERT\")) return sql;\n\n // Extract table name: INSERT INTO <table> ...\n const match = sql.match(/INSERT\\s+INTO\\s+[\"']?(\\w+)[\"']?/i);\n if (!match) return sql;\n\n const tableName = match[1];\n\n // Determine which columns to inject\n const injections: { col: string; value: string }[] = [];\n\n if (\n scoping.userEmail &&\n scoping.ownerEmailTables.has(tableName) &&\n !/owner_email/i.test(sql)\n ) {\n injections.push({\n col: \"owner_email\",\n value: `'${scoping.userEmail.replace(/'/g, \"''\")}'`,\n });\n }\n\n if (\n scoping.orgId &&\n scoping.orgIdTables.has(tableName) &&\n !/org_id/i.test(sql)\n ) {\n injections.push({\n col: \"org_id\",\n value: `'${scoping.orgId.replace(/'/g, \"''\")}'`,\n });\n }\n\n if (injections.length === 0) return sql;\n\n // Try to inject into explicit column list: INSERT INTO t (cols) VALUES (vals)\n const colListMatch = sql.match(\n /(INSERT\\s+INTO\\s+[\"']?\\w+[\"']?\\s*)\\(([^)]+)\\)(\\s*VALUES\\s*)\\(([^)]+)\\)/i,\n );\n if (colListMatch) {\n const [, prefix, cols, valueKeyword, vals] = colListMatch;\n const extraCols = injections.map((i) => i.col).join(\", \");\n const extraVals = injections.map((i) => i.value).join(\", \");\n return `${prefix}(${cols}, ${extraCols})${valueKeyword}(${vals}, ${extraVals})`;\n }\n\n return sql;\n}\n\nfunction escapeSqlString(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\nfunction sqliteScopePredicate(\n tableName: string,\n scoping: ScopingContext,\n): string | null {\n if (tableName === \"tool_data\" && scoping.userEmail) {\n const userClause = `(scope = 'user' AND owner_email = '${escapeSqlString(scoping.userEmail)}')`;\n const orgClause = scoping.orgId\n ? ` OR (scope = 'org' AND org_id = '${escapeSqlString(scoping.orgId)}')`\n : \"\";\n return `(${userClause}${orgClause})`;\n }\n\n const clauses: string[] = [];\n if (scoping.userEmail && scoping.ownerEmailTables.has(tableName)) {\n clauses.push(`owner_email = '${escapeSqlString(scoping.userEmail)}'`);\n }\n if (scoping.orgId && scoping.orgIdTables.has(tableName)) {\n clauses.push(`org_id = '${escapeSqlString(scoping.orgId)}'`);\n }\n return clauses.length > 0 ? clauses.join(\" AND \") : null;\n}\n\nfunction splitReturning(sql: string): { body: string; returning: string } {\n const match = /\\bRETURNING\\b/i.exec(sql);\n if (!match) return { body: sql, returning: \"\" };\n return {\n body: sql.slice(0, match.index).trimEnd(),\n returning: sql.slice(match.index),\n };\n}\n\nfunction addSqliteScopeToWhere(sql: string, predicate: string): string {\n const { body, returning } = splitReturning(sql);\n const whereMatch = /\\bWHERE\\b/i.exec(body);\n const scoped = whereMatch\n ? `${body.slice(0, whereMatch.index)}WHERE ${predicate} AND (${body.slice(whereMatch.index + whereMatch[0].length).trim()})`\n : `${body} WHERE ${predicate}`;\n return returning ? `${scoped} ${returning}` : scoped;\n}\n\nfunction qualifySqliteWrite(sql: string, scoping: ScopingContext): string {\n if (!scoping.active) return sql;\n\n const updateMatch = sql.match(/^\\s*UPDATE\\s+(?:\"([^\"]+)\"|'([^']+)'|(\\w+))/i);\n if (updateMatch) {\n const tableName = updateMatch[1] ?? updateMatch[2] ?? updateMatch[3];\n const predicate = sqliteScopePredicate(tableName, scoping);\n if (!predicate) return sql;\n const qualified = sql.replace(\n /^\\s*UPDATE\\s+(?:\"[^\"]+\"|'[^']+'|\\w+)/i,\n `UPDATE main.\"${tableName.replace(/\"/g, '\"\"')}\"`,\n );\n return addSqliteScopeToWhere(qualified, predicate);\n }\n\n const deleteMatch = sql.match(\n /^\\s*DELETE\\s+FROM\\s+(?:\"([^\"]+)\"|'([^']+)'|(\\w+))/i,\n );\n if (deleteMatch) {\n const tableName = deleteMatch[1] ?? deleteMatch[2] ?? deleteMatch[3];\n const predicate = sqliteScopePredicate(tableName, scoping);\n if (!predicate) return sql;\n const qualified = sql.replace(\n /^\\s*DELETE\\s+FROM\\s+(?:\"[^\"]+\"|'[^']+'|\\w+)/i,\n `DELETE FROM main.\"${tableName.replace(/\"/g, '\"\"')}\"`,\n );\n return addSqliteScopeToWhere(qualified, predicate);\n }\n\n return sql.replace(\n /^\\s*(INSERT\\s+INTO|REPLACE\\s+INTO)\\s+(?:\"([^\"]+)\"|'([^']+)'|(\\w+))/i,\n (match, keyword, quotedDouble, quotedSingle, bare) => {\n const tableName = quotedDouble ?? quotedSingle ?? bare;\n if (\n !scoping.ownerEmailTables.has(tableName) &&\n !scoping.orgIdTables.has(tableName)\n ) {\n return match;\n }\n return `${keyword} main.\"${tableName.replace(/\"/g, '\"\"')}\"`;\n },\n );\n}\n\nfunction printResult(\n sql: string,\n result: {\n count?: number;\n rowsAffected?: number;\n lastInsertRowid?: bigint | number;\n rows?: Record<string, unknown>[];\n },\n hasReturning: boolean,\n format?: string,\n) {\n if (hasReturning && result.rows && result.rows.length > 0) {\n if (format === \"json\") {\n console.log(\n JSON.stringify(\n { sql, rows: result.rows, count: result.rows.length },\n null,\n 2,\n ),\n );\n return;\n }\n console.log(`Executed: ${sql}`);\n console.log(`Returned ${result.rows.length} row(s):`);\n console.log(JSON.stringify(result.rows, null, 2));\n } else {\n const changes = result.count ?? result.rowsAffected ?? 0;\n if (format === \"json\") {\n console.log(\n JSON.stringify(\n {\n sql,\n changes,\n ...(result.lastInsertRowid && changes > 0\n ? { lastInsertRowid: Number(result.lastInsertRowid) }\n : {}),\n },\n null,\n 2,\n ),\n );\n return;\n }\n console.log(`Executed: ${sql}`);\n console.log(`Changes: ${changes}`);\n if (result.lastInsertRowid && changes > 0) {\n console.log(`Last Insert Row ID: ${result.lastInsertRowid}`);\n }\n if (changes === 0) {\n console.log(zeroChangesHint(sql));\n }\n }\n}\n\n/**\n * Hint emitted when an UPDATE/DELETE/REPLACE matches zero rows. Matches the\n * wording used by db-patch's \"no rows matched\" error so the agent gets the\n * same scoping nudge from both tools — without this hint, the agent reports\n * \"Changes: 0\" as success and the user sees no UI update because the row\n * either didn't exist or wasn't visible to the current user under per-user\n * scoping.\n */\nfunction zeroChangesHint(sql: string): string {\n const upper = sql.toUpperCase(); // leading whitespace already stripped by normalizeUserSql\n if (upper.startsWith(\"INSERT\")) {\n // INSERT changes=0 means INSERT OR IGNORE skipped a duplicate — different\n // failure mode, not a scoping issue.\n return \"Hint: 0 rows inserted. The row likely violated a UNIQUE / PRIMARY KEY constraint and was skipped (INSERT OR IGNORE).\";\n }\n return (\n \"Hint: 0 rows changed. The WHERE clause matched no rows — either the row \" +\n \"doesn't exist, or it exists but is owned by a different user (per-user \" +\n \"and per-org scoping is automatic for db-exec).\"\n );\n}\n\nfunction printBatchResult(results: DbExecResult[], format?: string): void {\n if (results.length === 1) {\n const result = results[0];\n printResult(\n result.sql,\n {\n count: result.changes,\n rowsAffected: result.changes,\n lastInsertRowid: result.lastInsertRowid,\n rows: result.rows,\n },\n Boolean(result.rows?.length),\n format,\n );\n return;\n }\n\n const totalChanges = results.reduce(\n (sum, result) => sum + Number(result.changes ?? 0),\n 0,\n );\n\n if (format === \"json\") {\n console.log(\n JSON.stringify(\n {\n statements: results.map((result) => ({\n index: result.index,\n sql: result.sql,\n changes: result.changes ?? 0,\n ...(result.lastInsertRowid && Number(result.changes ?? 0) > 0\n ? { lastInsertRowid: Number(result.lastInsertRowid) }\n : {}),\n ...(result.rows?.length\n ? { rows: result.rows, count: result.rows.length }\n : {}),\n })),\n changes: totalChanges,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(`Executed ${results.length} statements in one transaction.`);\n for (const result of results) {\n if (result.rows?.length) {\n console.log(`[${result.index}] Returned ${result.rows.length} row(s):`);\n console.log(JSON.stringify(result.rows, null, 2));\n } else {\n const changes = Number(result.changes ?? 0);\n console.log(`[${result.index}] Changes: ${changes}`);\n if (changes === 0) {\n console.log(`[${result.index}] ${zeroChangesHint(result.sql)}`);\n }\n }\n }\n console.log(`Total changes: ${totalChanges}`);\n}\n\nfunction sqliteRowsToObjects(\n rows: any[],\n columns: string[],\n): Record<string, unknown>[] {\n return rows.map((row) => {\n if (!Array.isArray(row) && row && typeof row === \"object\") {\n return { ...row };\n }\n const obj: Record<string, unknown> = {};\n for (let i = 0; i < columns.length; i++) {\n obj[columns[i]] = row[i];\n }\n return obj;\n });\n}\n\nexport default async function dbExec(args: string[]): Promise<void> {\n const parsed = parseArgs(args);\n\n if (parsed.help === \"true\") {\n console.log(`Usage: pnpm action db-exec --sql \"<statement>\" [options]\n pnpm action db-exec --statements '[{\"sql\":\"UPDATE ...\",\"args\":[...]}]' [options]\n\nOptions:\n --sql <stmt> Single INSERT / UPDATE / DELETE / REPLACE statement\n --args <json> JSON array of positional SQL bind parameters for --sql\n --statements <json> JSON array of {sql, args?}; runs in one transaction\n --db <path> Path to SQLite database (default: data/app.db)\n --format json Output as JSON\n --help Show this help message`);\n return;\n }\n\n const statements = parseStatements(parsed).map((statement, index) => ({\n sql: validateWriteSql(statement.sql, index + 1),\n args: statement.args,\n }));\n\n // Resolve database URL: --db flag → DATABASE_URL env → default file path\n let url: string;\n if (parsed.db) {\n url = \"file:\" + path.resolve(parsed.db);\n } else if (getDatabaseUrl()) {\n url = getDatabaseUrl();\n } else {\n url = \"file:\" + path.resolve(process.cwd(), \"data\", \"app.db\");\n }\n\n // Postgres path\n if (isPostgresUrl(url)) {\n const { default: pg } = await import(\"postgres\");\n const pgSql = pg(url);\n try {\n // Set up user-scoped temp views in production\n const scoping = await buildScopingPostgres(pgSql);\n\n const results: DbExecResult[] = [];\n await pgSql.begin(async (tx: any) => {\n try {\n // For UPDATE/DELETE: temp views scope to current user's rows.\n // Creating and dropping them inside the same transaction keeps\n // pooled Postgres backends from retaining session-local views.\n for (const stmt of scoping.setup) {\n await tx.unsafe(stmt);\n }\n\n for (let i = 0; i < statements.length; i++) {\n const statement = statements[i];\n const hasReturning = /\\bRETURNING\\b/i.test(statement.sql);\n const finalSql = normalizePostgresSql(\n injectOwnership(statement.sql, scoping),\n statement.args,\n );\n try {\n const result =\n statement.args.length > 0\n ? await tx.unsafe(finalSql, statement.args as any[])\n : await tx.unsafe(finalSql);\n const rows: Record<string, unknown>[] =\n hasReturning && result.length > 0 ? Array.from(result) : [];\n results.push({\n index: i + 1,\n sql: finalSql,\n changes: result.count ?? 0,\n rows,\n });\n } catch (err: any) {\n throw new Error(\n `Statement ${i + 1} failed: ${err?.message ?? String(err)}`,\n );\n }\n }\n } finally {\n for (const stmt of scoping.teardown) {\n await tx.unsafe(stmt).catch(() => {});\n }\n }\n });\n\n printBatchResult(results, parsed.format);\n } finally {\n await pgSql.end();\n }\n return;\n }\n\n // libsql / SQLite path\n const client = createClient({\n url,\n authToken: getDatabaseAuthToken(),\n });\n\n try {\n // Set up user-scoped temp views in production\n const scoping = await buildScopingSqlite(client);\n for (const stmt of scoping.setup) {\n await client.execute(stmt);\n }\n\n const results: DbExecResult[] = [];\n const shouldTransact = statements.length > 1;\n if (shouldTransact) await client.execute(\"BEGIN\");\n try {\n for (let i = 0; i < statements.length; i++) {\n const statement = statements[i];\n const hasReturning = /\\bRETURNING\\b/i.test(statement.sql);\n const finalSql = qualifySqliteWrite(\n injectOwnership(statement.sql, scoping),\n scoping,\n );\n try {\n const result =\n statement.args.length > 0\n ? await client.execute({\n sql: finalSql,\n args: statement.args as any[],\n })\n : await client.execute(finalSql);\n\n const rows: Record<string, unknown>[] =\n hasReturning && result.rows.length > 0\n ? sqliteRowsToObjects(result.rows, result.columns)\n : [];\n results.push({\n index: i + 1,\n sql: finalSql,\n changes: result.rowsAffected,\n lastInsertRowid: result.lastInsertRowid,\n rows,\n });\n } catch (err: any) {\n throw new Error(\n `Statement ${i + 1} failed: ${err?.message ?? String(err)}`,\n );\n }\n }\n if (shouldTransact) await client.execute(\"COMMIT\");\n } catch (err) {\n if (shouldTransact) {\n await client.execute(\"ROLLBACK\").catch(() => {});\n }\n throw err;\n }\n\n printBatchResult(results, parsed.format);\n\n for (const stmt of scoping.teardown) {\n await client.execute(stmt).catch(() => {});\n }\n } finally {\n client.close();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAczE,CAAC"}
|
package/dist/scripts/db/index.js
CHANGED
|
@@ -6,5 +6,6 @@ export const coreDbScripts = {
|
|
|
6
6
|
"db-check-scoping": (args) => import("./check-scoping.js").then((m) => m.default(args)),
|
|
7
7
|
"db-wipe-leaked-builder-keys": (args) => import("./wipe-leaked-builder-keys.js").then((m) => m.default(args)),
|
|
8
8
|
"db-migrate-user-api-keys": (args) => import("./migrate-user-api-keys.js").then((m) => m.default(args)),
|
|
9
|
+
"db-reset-dev-owner": (args) => import("./reset-dev-owner.js").then((m) => m.default(args)),
|
|
9
10
|
};
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scripts/db/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GACxB;IACE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,IAAI,EAAE,EAAE,CAC3B,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,6BAA6B,EAAE,CAAC,IAAI,EAAE,EAAE,CACtC,MAAM,CAAC,+BAA+B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CACnC,MAAM,CAAC,4BAA4B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scripts/db/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GACxB;IACE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,IAAI,EAAE,EAAE,CAC3B,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,6BAA6B,EAAE,CAAC,IAAI,EAAE,EAAE,CACtC,MAAM,CAAC,+BAA+B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CACnC,MAAM,CAAC,4BAA4B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAC7B,MAAM,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D,CAAC","sourcesContent":["export const coreDbScripts: Record<string, (args: string[]) => Promise<void>> =\n {\n \"db-schema\": (args) => import(\"./schema.js\").then((m) => m.default(args)),\n \"db-query\": (args) => import(\"./query.js\").then((m) => m.default(args)),\n \"db-exec\": (args) => import(\"./exec.js\").then((m) => m.default(args)),\n \"db-patch\": (args) => import(\"./patch.js\").then((m) => m.default(args)),\n \"db-check-scoping\": (args) =>\n import(\"./check-scoping.js\").then((m) => m.default(args)),\n \"db-wipe-leaked-builder-keys\": (args) =>\n import(\"./wipe-leaked-builder-keys.js\").then((m) => m.default(args)),\n \"db-migrate-user-api-keys\": (args) =>\n import(\"./migrate-user-api-keys.js\").then((m) => m.default(args)),\n \"db-reset-dev-owner\": (args) =>\n import(\"./reset-dev-owner.js\").then((m) => m.default(args)),\n };\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core script: db-reset-dev-owner
|
|
3
|
+
*
|
|
4
|
+
* One-shot fix for local DBs that accumulated rows owned by the dev
|
|
5
|
+
* sentinel `local@localhost`. Pre-changes-53, db-exec / db-query /
|
|
6
|
+
* db-patch silently fell back to that owner when no real identity was
|
|
7
|
+
* present, so any data created via CLI runs (or by older versions of
|
|
8
|
+
* the runner) landed under the sentinel and is now invisible to the
|
|
9
|
+
* actual signed-in user.
|
|
10
|
+
*
|
|
11
|
+
* This script discovers every ownable table (those with an
|
|
12
|
+
* `owner_email` column), then re-points each `local@localhost` row to
|
|
13
|
+
* the email passed via `--to`. Optionally restricted to a single table
|
|
14
|
+
* with `--table`.
|
|
15
|
+
*
|
|
16
|
+
* Local-dev-only safety: refuses to run when `NODE_ENV=production` or
|
|
17
|
+
* when targeting a non-`file:` SQLite URL (no Postgres / Turso /
|
|
18
|
+
* shared-DB writes).
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* pnpm action db-reset-dev-owner --to matthew@builder.io
|
|
22
|
+
* pnpm action db-reset-dev-owner --to matthew@builder.io --dry-run
|
|
23
|
+
* pnpm action db-reset-dev-owner --to matthew@builder.io --table decks
|
|
24
|
+
* pnpm action db-reset-dev-owner --to matthew@builder.io --db ./data/app.db
|
|
25
|
+
*/
|
|
26
|
+
export default function dbResetDevOwner(args: string[]): Promise<void>;
|
|
27
|
+
//# sourceMappingURL=reset-dev-owner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset-dev-owner.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/reset-dev-owner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAkEH,wBAA8B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuE3E"}
|