@agent-native/core 0.12.25 → 0.12.29
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/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/model-config.d.ts +3 -3
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +5 -4
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +20 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/application-state/emitter.d.ts +3 -2
- package/dist/application-state/emitter.d.ts.map +1 -1
- package/dist/application-state/emitter.js +4 -2
- package/dist/application-state/emitter.js.map +1 -1
- package/dist/application-state/store.js +3 -3
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +0 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AgentTaskCard.d.ts.map +1 -1
- package/dist/client/AgentTaskCard.js +16 -3
- package/dist/client/AgentTaskCard.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +67 -19
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/IframeEmbed.d.ts.map +1 -1
- package/dist/client/IframeEmbed.js +2 -2
- package/dist/client/IframeEmbed.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +74 -14
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +1 -1
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +8 -7
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/attachment-accept.d.ts +7 -0
- package/dist/client/composer/attachment-accept.d.ts.map +1 -0
- package/dist/client/composer/attachment-accept.js +36 -0
- package/dist/client/composer/attachment-accept.js.map +1 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +8 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +38 -13
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-pausing-interval.d.ts.map +1 -1
- package/dist/client/use-pausing-interval.js +5 -2
- package/dist/client/use-pausing-interval.js.map +1 -1
- package/dist/collab/client.d.ts +2 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +37 -4
- package/dist/collab/client.js.map +1 -1
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +70 -34
- package/dist/db/client.js.map +1 -1
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +30 -7
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/deploy/build.js +64 -0
- package/dist/deploy/build.js.map +1 -1
- package/dist/scripts/db/exec.d.ts.map +1 -1
- package/dist/scripts/db/exec.js +3 -6
- package/dist/scripts/db/exec.js.map +1 -1
- package/dist/scripts/db/patch.d.ts.map +1 -1
- package/dist/scripts/db/patch.js +3 -6
- package/dist/scripts/db/patch.js.map +1 -1
- package/dist/scripts/db/query.d.ts.map +1 -1
- package/dist/scripts/db/query.js +3 -6
- package/dist/scripts/db/query.js.map +1 -1
- package/dist/scripts/db/schema.d.ts.map +1 -1
- package/dist/scripts/db/schema.js +3 -6
- package/dist/scripts/db/schema.js.map +1 -1
- package/dist/scripts/db/sqlite-client.d.ts +15 -0
- package/dist/scripts/db/sqlite-client.d.ts.map +1 -0
- package/dist/scripts/db/sqlite-client.js +51 -0
- package/dist/scripts/db/sqlite-client.js.map +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +83 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.js +4 -3
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/google-auth-plugin.d.ts.map +1 -1
- package/dist/server/google-auth-plugin.js +50 -3
- package/dist/server/google-auth-plugin.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +10 -4
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +50 -3
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +15 -0
- package/dist/server/poll.js.map +1 -1
- package/dist/templates/default/app/hooks/use-navigation-state.ts +0 -1
- package/package.json +1 -1
- package/src/templates/default/app/hooks/use-navigation-state.ts +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/scripts/db/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAExE,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,YAAY,CAAC,GAAuB;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;IAC5C,CAAC;IACD,IAAI,CAAC,6BAA6B,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,oCAAoC,CAAC,GAAW;IACvD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,KAAK,GACP,QAAQ,CAAC;IAEX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAClB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAExB,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;YAC7B,GAAG,IAAI,EAAE,CAAC;YACV,IAAI,EAAE,KAAK,IAAI;gBAAE,KAAK,GAAG,QAAQ,CAAC;YAClC,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;YAC9B,GAAG,IAAI,EAAE,CAAC;YACV,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAC/B,GAAG,IAAI,IAAI,CAAC;gBACZ,CAAC,EAAE,CAAC;gBACJ,KAAK,GAAG,QAAQ,CAAC;YACnB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,GAAG,IAAI,EAAE,CAAC;YACV,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAC/B,GAAG,IAAI,IAAI,CAAC;gBACZ,CAAC,EAAE,CAAC;YACN,CAAC;iBAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBACtB,KAAK,GAAG,QAAQ,CAAC;YACnB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,GAAG,IAAI,EAAE,CAAC;YACV,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAC/B,GAAG,IAAI,IAAI,CAAC;gBACZ,CAAC,EAAE,CAAC;YACN,CAAC;iBAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBACtB,KAAK,GAAG,QAAQ,CAAC;YACnB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAC/B,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;YACjB,CAAC,EAAE,CAAC;YACJ,KAAK,GAAG,cAAc,CAAC;YACvB,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAC/B,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;YACjB,CAAC,EAAE,CAAC;YACJ,KAAK,GAAG,eAAe,CAAC;YACxB,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,GAAG,IAAI,EAAE,CAAC;YACV,KAAK,GAAG,QAAQ,CAAC;YACjB,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,GAAG,IAAI,EAAE,CAAC;YACV,KAAK,GAAG,QAAQ,CAAC;YACjB,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,KAAK,EAAE,CAAC;YACR,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QACD,GAAG,IAAI,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAW,EAAE,IAAe;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACzD,OAAO,oCAAoC,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,UAAU,CACjB,IAA+B,EAC/B,QAAgB,EAChB,MAAe;IAEf,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CACvE,CAAC;QACF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAEtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAE1D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,IAAI;aACd,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACZ,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;YACrC,OAAO,GAAG,CAAC,MAAM,GAAG,EAAE;gBACpB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK;gBAC1B,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC;aACD,IAAI,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,OAAO,CAAC,IAAc;IAClD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC;;;;;;;;yCAQyB,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;IACvB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,yDAAyD,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE1C,2CAA2C;IAC3C,yDAAyD;IACzD,MAAM,QAAQ,GAAG,GAAG;SACjB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,IAAI,EAAE,CAAC;IACV,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IACE,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC3B,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QACzB,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5B,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,EAC3B,CAAC;QACD,IAAI,CACF,qFAAqF,CACtF,CAAC;IACJ,CAAC;IACD,gCAAgC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEnD,yEAAyE;IACzE,IAAI,GAAW,CAAC;IAChB,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,GAAG,GAAG,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;SAAM,IAAI,cAAc,EAAE,EAAE,CAAC;QAC5B,GAAG,GAAG,cAAc,EAAE,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,QAAQ,GAAG,GAAG,CAAC;IACnB,IACE,MAAM,CAAC,KAAK;QACZ,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACxD,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,EAC5B,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;YACjC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QAC7C,QAAQ,GAAG,GAAG,GAAG,UAAU,QAAQ,EAAE,CAAC;IACxC,CAAC;IAED,gBAAgB;IAChB,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC1D,IAAI,IAAI,GAA8B,EAAE,CAAC;YACzC,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,EAAO,EAAE,EAAE;gBAClC,iEAAiE;gBACjE,mEAAmE;gBACnE,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,EAAE,CAAC,CAAC;gBAC/C,IAAI,CAAC;oBACH,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;wBACjC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACxB,CAAC;oBAED,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,CAAC;wBAChB,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,OAAgB,CAAC;wBAC9C,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBACjC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC5B,CAAC;wBAAS,CAAC;oBACT,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;wBACpC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACxC,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAEzD,UAAU,CACR,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EACpD,SAAS,EACT,MAAM,CAAC,MAAM,CACd,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC;QACpB,CAAC;QACD,OAAO;IACT,CAAC;IAED,uBAAuB;IACvB,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,GAAG;QACH,SAAS,EAAE,oBAAoB,EAAE;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,8CAA8C;QAC9C,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,CAAC;YAChB,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC;YACjE,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,IAAI,GAA8B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAC9D,MAAM,GAAG,GAA4B,EAAE,CAAC;YACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAE1C,uBAAuB;QACvB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;AACH,CAAC","sourcesContent":["/**\n * Core script: db-query\n *\n * Run a read-only SQL query against a SQLite or Postgres database.\n *\n * In production mode, temporary views are created to scope data to the\n * current user (AGENT_USER_EMAIL). Tables with an `owner_email` column\n * and core tables (settings, application_state, etc.) are automatically\n * filtered so queries only return the current user's data.\n *\n * Usage:\n * pnpm action db-query --sql \"SELECT * FROM forms WHERE id = ?\" [--args '[\"abc\"]'] [--db path] [--format json] [--limit N]\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 { assertNoSensitiveFrameworkTables } from \"./safety.js\";\nimport { buildScopingPostgres, buildScopingSqlite } from \"./scoping.js\";\n\nfunction isPostgresUrl(url: string): boolean {\n return url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\");\n}\n\nfunction parseSqlArgs(raw: string | undefined): 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(\"--args must be a JSON array\");\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\nfunction printTable(\n rows: Record<string, unknown>[],\n finalSql: string,\n format?: string,\n) {\n if (format === \"json\") {\n console.log(\n JSON.stringify({ query: finalSql, rows, count: rows.length }, null, 2),\n );\n return;\n }\n\n console.log(`Query: ${finalSql}`);\n console.log(`Rows: ${rows.length}\\n`);\n\n if (rows.length === 0) {\n console.log(\"(no results)\");\n return;\n }\n\n const keys = Object.keys(rows[0]);\n const widths = keys.map((k) => {\n const maxVal = Math.max(...rows.map((r) => String(r[k] ?? \"NULL\").length));\n return Math.max(k.length, Math.min(maxVal, 60));\n });\n\n const header = keys.map((k, i) => k.padEnd(widths[i])).join(\" | \");\n console.log(header);\n console.log(widths.map((w) => \"-\".repeat(w)).join(\"-+-\"));\n\n for (const row of rows) {\n const line = keys\n .map((k, i) => {\n const val = String(row[k] ?? \"NULL\");\n return val.length > 60\n ? val.slice(0, 57) + \"...\"\n : val.padEnd(widths[i]);\n })\n .join(\" | \");\n console.log(line);\n }\n}\n\nexport default async function dbQuery(args: string[]): Promise<void> {\n const parsed = parseArgs(args);\n\n if (parsed.help === \"true\") {\n console.log(`Usage: pnpm action db-query --sql \"<query>\" [options]\n\nOptions:\n --sql <query> SQL SELECT query to run (required)\n --args <json> JSON array of positional SQL bind parameters\n --db <path> Path to SQLite database (default: data/app.db)\n --format json Output as JSON instead of a table\n --limit N Append LIMIT N if not already present\n --help Show this help message`);\n return;\n }\n\n const sql = parsed.sql;\n if (!sql) {\n fail('--sql is required. Example: --sql \"SELECT * FROM forms\"');\n }\n const sqlArgs = parseSqlArgs(parsed.args);\n\n // Safety: only allow read-only statements.\n // Strip leading SQL comments before checking the prefix.\n const stripped = sql\n .replace(/^\\s*--[^\\n]*\\n/gm, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .trim();\n const upper = stripped.toUpperCase();\n if (\n !upper.startsWith(\"SELECT\") &&\n !upper.startsWith(\"WITH\") &&\n !upper.startsWith(\"EXPLAIN\") &&\n !upper.startsWith(\"PRAGMA\")\n ) {\n fail(\n \"Only SELECT, WITH, EXPLAIN, and PRAGMA queries are allowed. Use db-exec for writes.\",\n );\n }\n assertNoSensitiveFrameworkTables(stripped, \"read\");\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 let finalSql = sql;\n if (\n parsed.limit &&\n (upper.startsWith(\"SELECT\") || upper.startsWith(\"WITH\")) &&\n !/\\bLIMIT\\b/i.test(stripped)\n ) {\n const limitVal = parseInt(parsed.limit, 10);\n if (isNaN(limitVal) || limitVal < 1)\n fail(\"--limit must be a positive integer\");\n finalSql = `${sql} LIMIT ${limitVal}`;\n }\n\n // Postgres path\n if (isPostgresUrl(url)) {\n const { default: pg } = await import(\"postgres\");\n const pgSql = pg(url);\n try {\n const pgSqlText = normalizePostgresSql(finalSql, sqlArgs);\n let rows: Record<string, unknown>[] = [];\n await pgSql.begin(async (tx: any) => {\n // Temp views are session state. Keep setup/query/teardown on one\n // transaction-bound backend so pooled Postgres never retains them.\n const scoping = await buildScopingPostgres(tx);\n try {\n for (const stmt of scoping.setup) {\n await tx.unsafe(stmt);\n }\n\n const result =\n sqlArgs.length > 0\n ? await tx.unsafe(pgSqlText, sqlArgs as any[])\n : await tx.unsafe(pgSqlText);\n rows = Array.from(result);\n } finally {\n for (const stmt of scoping.teardown) {\n await tx.unsafe(stmt).catch(() => {});\n }\n }\n });\n const keys = rows.length > 0 ? Object.keys(rows[0]) : [];\n\n printTable(\n rows.length > 0 ? rows : keys.length > 0 ? rows : [],\n pgSqlText,\n parsed.format,\n );\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 result =\n sqlArgs.length > 0\n ? await client.execute({ sql: finalSql, args: sqlArgs as any[] })\n : await client.execute(finalSql);\n const rows: Record<string, unknown>[] = result.rows.map((row) => {\n const obj: Record<string, unknown> = {};\n for (let i = 0; i < result.columns.length; i++) {\n obj[result.columns[i]] = row[i];\n }\n return obj;\n });\n\n printTable(rows, finalSql, parsed.format);\n\n // Tear down temp views\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":"query.js","sourceRoot":"","sources":["../../../src/scripts/db/query.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Core script: db-query\n *\n * Run a read-only SQL query against a SQLite or Postgres database.\n *\n * In production mode, temporary views are created to scope data to the\n * current user (AGENT_USER_EMAIL). Tables with an `owner_email` column\n * and core tables (settings, application_state, etc.) are automatically\n * filtered so queries only return the current user's data.\n *\n * Usage:\n * pnpm action db-query --sql \"SELECT * FROM forms WHERE id = ?\" [--args '[\"abc\"]'] [--db path] [--format json] [--limit N]\n */\n\nimport path from \"path\";\nimport { getDatabaseUrl } from \"../../db/client.js\";\nimport { parseArgs, fail } from \"../utils.js\";\nimport { assertNoSensitiveFrameworkTables } from \"./safety.js\";\nimport { buildScopingPostgres, buildScopingSqlite } from \"./scoping.js\";\nimport { createSqliteScriptClient } from \"./sqlite-client.js\";\n\nfunction isPostgresUrl(url: string): boolean {\n return url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\");\n}\n\nfunction parseSqlArgs(raw: string | undefined): 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(\"--args must be a JSON array\");\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\nfunction printTable(\n rows: Record<string, unknown>[],\n finalSql: string,\n format?: string,\n) {\n if (format === \"json\") {\n console.log(\n JSON.stringify({ query: finalSql, rows, count: rows.length }, null, 2),\n );\n return;\n }\n\n console.log(`Query: ${finalSql}`);\n console.log(`Rows: ${rows.length}\\n`);\n\n if (rows.length === 0) {\n console.log(\"(no results)\");\n return;\n }\n\n const keys = Object.keys(rows[0]);\n const widths = keys.map((k) => {\n const maxVal = Math.max(...rows.map((r) => String(r[k] ?? \"NULL\").length));\n return Math.max(k.length, Math.min(maxVal, 60));\n });\n\n const header = keys.map((k, i) => k.padEnd(widths[i])).join(\" | \");\n console.log(header);\n console.log(widths.map((w) => \"-\".repeat(w)).join(\"-+-\"));\n\n for (const row of rows) {\n const line = keys\n .map((k, i) => {\n const val = String(row[k] ?? \"NULL\");\n return val.length > 60\n ? val.slice(0, 57) + \"...\"\n : val.padEnd(widths[i]);\n })\n .join(\" | \");\n console.log(line);\n }\n}\n\nexport default async function dbQuery(args: string[]): Promise<void> {\n const parsed = parseArgs(args);\n\n if (parsed.help === \"true\") {\n console.log(`Usage: pnpm action db-query --sql \"<query>\" [options]\n\nOptions:\n --sql <query> SQL SELECT query to run (required)\n --args <json> JSON array of positional SQL bind parameters\n --db <path> Path to SQLite database (default: data/app.db)\n --format json Output as JSON instead of a table\n --limit N Append LIMIT N if not already present\n --help Show this help message`);\n return;\n }\n\n const sql = parsed.sql;\n if (!sql) {\n fail('--sql is required. Example: --sql \"SELECT * FROM forms\"');\n }\n const sqlArgs = parseSqlArgs(parsed.args);\n\n // Safety: only allow read-only statements.\n // Strip leading SQL comments before checking the prefix.\n const stripped = sql\n .replace(/^\\s*--[^\\n]*\\n/gm, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .trim();\n const upper = stripped.toUpperCase();\n if (\n !upper.startsWith(\"SELECT\") &&\n !upper.startsWith(\"WITH\") &&\n !upper.startsWith(\"EXPLAIN\") &&\n !upper.startsWith(\"PRAGMA\")\n ) {\n fail(\n \"Only SELECT, WITH, EXPLAIN, and PRAGMA queries are allowed. Use db-exec for writes.\",\n );\n }\n assertNoSensitiveFrameworkTables(stripped, \"read\");\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 let finalSql = sql;\n if (\n parsed.limit &&\n (upper.startsWith(\"SELECT\") || upper.startsWith(\"WITH\")) &&\n !/\\bLIMIT\\b/i.test(stripped)\n ) {\n const limitVal = parseInt(parsed.limit, 10);\n if (isNaN(limitVal) || limitVal < 1)\n fail(\"--limit must be a positive integer\");\n finalSql = `${sql} LIMIT ${limitVal}`;\n }\n\n // Postgres path\n if (isPostgresUrl(url)) {\n const { default: pg } = await import(\"postgres\");\n const pgSql = pg(url);\n try {\n const pgSqlText = normalizePostgresSql(finalSql, sqlArgs);\n let rows: Record<string, unknown>[] = [];\n await pgSql.begin(async (tx: any) => {\n // Temp views are session state. Keep setup/query/teardown on one\n // transaction-bound backend so pooled Postgres never retains them.\n const scoping = await buildScopingPostgres(tx);\n try {\n for (const stmt of scoping.setup) {\n await tx.unsafe(stmt);\n }\n\n const result =\n sqlArgs.length > 0\n ? await tx.unsafe(pgSqlText, sqlArgs as any[])\n : await tx.unsafe(pgSqlText);\n rows = Array.from(result);\n } finally {\n for (const stmt of scoping.teardown) {\n await tx.unsafe(stmt).catch(() => {});\n }\n }\n });\n const keys = rows.length > 0 ? Object.keys(rows[0]) : [];\n\n printTable(\n rows.length > 0 ? rows : keys.length > 0 ? rows : [],\n pgSqlText,\n parsed.format,\n );\n } finally {\n await pgSql.end();\n }\n return;\n }\n\n // libsql / SQLite path\n const client = await createSqliteScriptClient(url);\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 result =\n sqlArgs.length > 0\n ? await client.execute({ sql: finalSql, args: sqlArgs as any[] })\n : await client.execute(finalSql);\n const rows: Record<string, unknown>[] = result.rows.map((row) => {\n const obj: Record<string, unknown> = {};\n for (let i = 0; i < result.columns.length; i++) {\n obj[result.columns[i]] = row[i];\n }\n return obj;\n });\n\n printTable(rows, finalSql, parsed.format);\n\n // Tear down temp views\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":"schema.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA0NH,wBAA8B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuIpE"}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* pnpm action db-schema [--db path] [--format json]
|
|
10
10
|
*/
|
|
11
11
|
import path from "path";
|
|
12
|
-
import {
|
|
13
|
-
import { getDatabaseUrl, getDatabaseAuthToken } from "../../db/client.js";
|
|
12
|
+
import { getDatabaseUrl } from "../../db/client.js";
|
|
14
13
|
import { parseArgs } from "../utils.js";
|
|
14
|
+
import { createSqliteScriptClient, } from "./sqlite-client.js";
|
|
15
15
|
function isPostgresUrl(url) {
|
|
16
16
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
17
17
|
}
|
|
@@ -197,10 +197,7 @@ Options:
|
|
|
197
197
|
return introspectPostgres(url, parsed);
|
|
198
198
|
}
|
|
199
199
|
// SQLite / libsql path
|
|
200
|
-
const client =
|
|
201
|
-
url,
|
|
202
|
-
authToken: getDatabaseAuthToken(),
|
|
203
|
-
});
|
|
200
|
+
const client = await createSqliteScriptClient(url);
|
|
204
201
|
try {
|
|
205
202
|
const tablesResult = await client.execute(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
|
206
203
|
const tables = tablesResult.rows.map((row) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/scripts/db/schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Core script: db-schema\n *\n * Inspects a SQLite or Postgres database and prints all tables, columns, types,\n * constraints, and foreign keys. Gives the agent full visibility\n * into the app's data model.\n *\n * Usage:\n * pnpm action db-schema [--db path] [--format json]\n */\n\nimport path from \"path\";\nimport { createClient, type Client } from \"@libsql/client\";\nimport { getDatabaseUrl, getDatabaseAuthToken } from \"../../db/client.js\";\nimport { parseArgs, fail } from \"../utils.js\";\n\ninterface ColumnInfo {\n name: string;\n type: string;\n notnull: boolean;\n pk: boolean;\n dflt_value: string | null;\n}\n\ninterface ForeignKey {\n from: string;\n table: string;\n to: string;\n}\n\ninterface TableInfo {\n name: string;\n columns: ColumnInfo[];\n foreignKeys: ForeignKey[];\n indexes: { name: string; unique: boolean; columns: string[] }[];\n}\n\nfunction isPostgresUrl(url: string): boolean {\n return url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\");\n}\n\nfunction databaseLabel(url: string): string {\n if (url.startsWith(\"file:\")) return url.slice(5);\n try {\n const parsed = new URL(url);\n const auth = parsed.username ? `${parsed.username}:***@` : \"\";\n return `${parsed.protocol}//${auth}${parsed.host}${parsed.pathname}`;\n } catch {\n return url.replace(/:\\/\\/([^:@\\s]+):([^@\\s]+)@/, \"://$1:***@\");\n }\n}\n\n/**\n * Execute a PRAGMA query and return the rows as plain objects.\n */\nasync function pragma(\n client: Client,\n pragmaQuery: string,\n): Promise<Record<string, unknown>[]> {\n const result = await client.execute(pragmaQuery);\n return result.rows.map((row) => {\n const obj: Record<string, unknown> = {};\n for (let i = 0; i < result.columns.length; i++) {\n obj[result.columns[i]] = row[i];\n }\n return obj;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Postgres introspection\n// ---------------------------------------------------------------------------\n\nasync function introspectPostgres(\n url: string,\n parsed: Record<string, string>,\n): Promise<void> {\n const { default: pg } = await import(\"postgres\");\n const sql = pg(url);\n\n try {\n // List tables\n const tables: { name: string }[] = await sql`\n SELECT table_name as name\n FROM information_schema.tables\n WHERE table_schema = 'public' AND table_type = 'BASE TABLE'\n ORDER BY table_name\n `;\n\n const tableInfos: TableInfo[] = [];\n\n for (const t of tables) {\n // Columns\n const cols: any[] = await sql`\n SELECT\n column_name as name,\n data_type as type,\n CASE WHEN is_nullable = 'NO' THEN 1 ELSE 0 END as notnull,\n column_default as dflt_value\n FROM information_schema.columns\n WHERE table_name = ${t.name}\n ORDER BY ordinal_position\n `;\n\n // Primary keys\n const pks: any[] = await sql`\n SELECT kcu.column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.table_name = ${t.name}\n AND tc.constraint_type = 'PRIMARY KEY'\n `;\n const pkSet = new Set(pks.map((p) => p.column_name));\n\n // Foreign keys\n const fks: any[] = await sql`\n SELECT\n kcu.column_name as \"from\",\n ccu.table_name as \"table\",\n ccu.column_name as \"to\"\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n WHERE tc.table_name = ${t.name}\n AND tc.constraint_type = 'FOREIGN KEY'\n `;\n\n // Indexes\n const idxRows: any[] = await sql`\n SELECT indexname as name, indexdef\n FROM pg_indexes\n WHERE tablename = ${t.name} AND schemaname = 'public'\n `;\n const indexes = idxRows.map((idx) => {\n const unique = /\\bUNIQUE\\b/i.test(idx.indexdef);\n // Extract column list from CREATE INDEX ... (col1, col2)\n const colMatch = idx.indexdef.match(/\\(([^)]+)\\)/);\n const columns = colMatch\n ? colMatch[1].split(\",\").map((c: string) => c.trim())\n : [];\n return { name: idx.name, unique, columns };\n });\n\n tableInfos.push({\n name: t.name,\n columns: cols.map((c) => ({\n name: c.name,\n type: c.type || \"ANY\",\n notnull: c.notnull === 1,\n pk: pkSet.has(c.name),\n dflt_value: c.dflt_value as string | null,\n })),\n foreignKeys: fks.map((fk) => ({\n from: fk.from,\n table: fk.table,\n to: fk.to,\n })),\n indexes,\n });\n }\n\n if (parsed.format === \"json\") {\n console.log(\n JSON.stringify(\n { database: databaseLabel(url), tables: tableInfos },\n null,\n 2,\n ),\n );\n return;\n }\n\n // Human-readable output\n console.log(`Database: ${databaseLabel(url)}`);\n console.log(`Tables: ${tableInfos.length}\\n`);\n\n for (const table of tableInfos) {\n console.log(`Table: ${table.name} (${table.columns.length} columns)`);\n\n const fkMap = new Map<string, string>();\n for (const fk of table.foreignKeys) {\n fkMap.set(fk.from, `${fk.table}(${fk.to})`);\n }\n\n const nameWidth = Math.max(...table.columns.map((c) => c.name.length));\n const typeWidth = Math.max(...table.columns.map((c) => c.type.length));\n\n for (const col of table.columns) {\n const parts: string[] = [];\n if (col.pk) parts.push(\"PRIMARY KEY\");\n if (col.notnull && !col.pk) parts.push(\"NOT NULL\");\n if (col.dflt_value !== null) parts.push(`DEFAULT ${col.dflt_value}`);\n const fkRef = fkMap.get(col.name);\n if (fkRef) parts.push(`→ ${fkRef}`);\n\n const constraint = parts.length > 0 ? ` ${parts.join(\", \")}` : \"\";\n console.log(\n ` ${col.name.padEnd(nameWidth)} ${col.type.padEnd(typeWidth)}${constraint}`,\n );\n }\n\n if (table.indexes.length > 0) {\n console.log(` Indexes:`);\n for (const idx of table.indexes) {\n const unique = idx.unique ? \"UNIQUE \" : \"\";\n console.log(` ${unique}${idx.name} (${idx.columns.join(\", \")})`);\n }\n }\n\n console.log();\n }\n } finally {\n await sql.end();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Main entry\n// ---------------------------------------------------------------------------\n\nexport default async function dbSchema(args: string[]): Promise<void> {\n const parsed = parseArgs(args);\n\n if (parsed.help === \"true\") {\n console.log(`Usage: pnpm action db-schema [--db <path>] [--format json]\n\nOptions:\n --db <path> Path to SQLite database (default: data/app.db)\n --format json Output as JSON instead of human-readable text\n --help Show this help message`);\n return;\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 return introspectPostgres(url, parsed);\n }\n\n // SQLite / libsql path\n const client = createClient({\n url,\n authToken: getDatabaseAuthToken(),\n });\n\n try {\n const tablesResult = await client.execute(\n `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`,\n );\n const tables = tablesResult.rows.map((row) => ({\n name: row[0] as string,\n }));\n\n const tableInfos: TableInfo[] = [];\n\n for (const t of tables) {\n const escaped = t.name.replace(/\"/g, '\"\"');\n\n const columns = await pragma(client, `PRAGMA table_info(\"${escaped}\")`);\n const fks = await pragma(client, `PRAGMA foreign_key_list(\"${escaped}\")`);\n const idxList = await pragma(client, `PRAGMA index_list(\"${escaped}\")`);\n\n const indexes: { name: string; unique: boolean; columns: string[] }[] =\n [];\n for (const idx of idxList) {\n const idxName = idx.name as string;\n if (idxName.startsWith(\"sqlite_\")) continue;\n const idxInfo = await pragma(\n client,\n `PRAGMA index_info(\"${idxName.replace(/\"/g, '\"\"')}\")`,\n );\n indexes.push({\n name: idxName,\n unique: idx.unique === 1,\n columns: idxInfo.map((c) => c.name as string),\n });\n }\n\n tableInfos.push({\n name: t.name,\n columns: columns.map((c) => ({\n name: c.name as string,\n type: (c.type as string) || \"ANY\",\n notnull: c.notnull === 1,\n pk: c.pk === 1,\n dflt_value: c.dflt_value as string | null,\n })),\n foreignKeys: fks.map((fk) => ({\n from: fk.from as string,\n table: fk.table as string,\n to: fk.to as string,\n })),\n indexes,\n });\n }\n\n if (parsed.format === \"json\") {\n const dbLabel = databaseLabel(url);\n console.log(\n JSON.stringify({ database: dbLabel, tables: tableInfos }, null, 2),\n );\n return;\n }\n\n // Human-readable output\n const dbLabel = databaseLabel(url);\n console.log(`Database: ${dbLabel}`);\n console.log(`Tables: ${tableInfos.length}\\n`);\n\n for (const table of tableInfos) {\n console.log(`Table: ${table.name} (${table.columns.length} columns)`);\n\n // Build FK lookup for annotation\n const fkMap = new Map<string, string>();\n for (const fk of table.foreignKeys) {\n fkMap.set(fk.from, `${fk.table}(${fk.to})`);\n }\n\n // Find max widths for alignment\n const nameWidth = Math.max(...table.columns.map((c) => c.name.length));\n const typeWidth = Math.max(...table.columns.map((c) => c.type.length));\n\n for (const col of table.columns) {\n const parts: string[] = [];\n if (col.pk) parts.push(\"PRIMARY KEY\");\n if (col.notnull && !col.pk) parts.push(\"NOT NULL\");\n if (col.dflt_value !== null) parts.push(`DEFAULT ${col.dflt_value}`);\n const fkRef = fkMap.get(col.name);\n if (fkRef) parts.push(`→ ${fkRef}`);\n\n const constraint = parts.length > 0 ? ` ${parts.join(\", \")}` : \"\";\n console.log(\n ` ${col.name.padEnd(nameWidth)} ${col.type.padEnd(typeWidth)}${constraint}`,\n );\n }\n\n if (table.indexes.length > 0) {\n console.log(` Indexes:`);\n for (const idx of table.indexes) {\n const unique = idx.unique ? \"UNIQUE \" : \"\";\n console.log(` ${unique}${idx.name} (${idx.columns.join(\", \")})`);\n }\n }\n\n console.log();\n }\n } finally {\n client.close();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/scripts/db/schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Core script: db-schema\n *\n * Inspects a SQLite or Postgres database and prints all tables, columns, types,\n * constraints, and foreign keys. Gives the agent full visibility\n * into the app's data model.\n *\n * Usage:\n * pnpm action db-schema [--db path] [--format json]\n */\n\nimport path from \"path\";\nimport { getDatabaseUrl } from \"../../db/client.js\";\nimport { parseArgs, fail } from \"../utils.js\";\nimport {\n createSqliteScriptClient,\n type SqliteScriptClient,\n} from \"./sqlite-client.js\";\n\ninterface ColumnInfo {\n name: string;\n type: string;\n notnull: boolean;\n pk: boolean;\n dflt_value: string | null;\n}\n\ninterface ForeignKey {\n from: string;\n table: string;\n to: string;\n}\n\ninterface TableInfo {\n name: string;\n columns: ColumnInfo[];\n foreignKeys: ForeignKey[];\n indexes: { name: string; unique: boolean; columns: string[] }[];\n}\n\nfunction isPostgresUrl(url: string): boolean {\n return url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\");\n}\n\nfunction databaseLabel(url: string): string {\n if (url.startsWith(\"file:\")) return url.slice(5);\n try {\n const parsed = new URL(url);\n const auth = parsed.username ? `${parsed.username}:***@` : \"\";\n return `${parsed.protocol}//${auth}${parsed.host}${parsed.pathname}`;\n } catch {\n return url.replace(/:\\/\\/([^:@\\s]+):([^@\\s]+)@/, \"://$1:***@\");\n }\n}\n\n/**\n * Execute a PRAGMA query and return the rows as plain objects.\n */\nasync function pragma(\n client: SqliteScriptClient,\n pragmaQuery: string,\n): Promise<Record<string, unknown>[]> {\n const result = await client.execute(pragmaQuery);\n return result.rows.map((row) => {\n const obj: Record<string, unknown> = {};\n for (let i = 0; i < result.columns.length; i++) {\n obj[result.columns[i]] = row[i];\n }\n return obj;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Postgres introspection\n// ---------------------------------------------------------------------------\n\nasync function introspectPostgres(\n url: string,\n parsed: Record<string, string>,\n): Promise<void> {\n const { default: pg } = await import(\"postgres\");\n const sql = pg(url);\n\n try {\n // List tables\n const tables: { name: string }[] = await sql`\n SELECT table_name as name\n FROM information_schema.tables\n WHERE table_schema = 'public' AND table_type = 'BASE TABLE'\n ORDER BY table_name\n `;\n\n const tableInfos: TableInfo[] = [];\n\n for (const t of tables) {\n // Columns\n const cols: any[] = await sql`\n SELECT\n column_name as name,\n data_type as type,\n CASE WHEN is_nullable = 'NO' THEN 1 ELSE 0 END as notnull,\n column_default as dflt_value\n FROM information_schema.columns\n WHERE table_name = ${t.name}\n ORDER BY ordinal_position\n `;\n\n // Primary keys\n const pks: any[] = await sql`\n SELECT kcu.column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.table_name = ${t.name}\n AND tc.constraint_type = 'PRIMARY KEY'\n `;\n const pkSet = new Set(pks.map((p) => p.column_name));\n\n // Foreign keys\n const fks: any[] = await sql`\n SELECT\n kcu.column_name as \"from\",\n ccu.table_name as \"table\",\n ccu.column_name as \"to\"\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n WHERE tc.table_name = ${t.name}\n AND tc.constraint_type = 'FOREIGN KEY'\n `;\n\n // Indexes\n const idxRows: any[] = await sql`\n SELECT indexname as name, indexdef\n FROM pg_indexes\n WHERE tablename = ${t.name} AND schemaname = 'public'\n `;\n const indexes = idxRows.map((idx) => {\n const unique = /\\bUNIQUE\\b/i.test(idx.indexdef);\n // Extract column list from CREATE INDEX ... (col1, col2)\n const colMatch = idx.indexdef.match(/\\(([^)]+)\\)/);\n const columns = colMatch\n ? colMatch[1].split(\",\").map((c: string) => c.trim())\n : [];\n return { name: idx.name, unique, columns };\n });\n\n tableInfos.push({\n name: t.name,\n columns: cols.map((c) => ({\n name: c.name,\n type: c.type || \"ANY\",\n notnull: c.notnull === 1,\n pk: pkSet.has(c.name),\n dflt_value: c.dflt_value as string | null,\n })),\n foreignKeys: fks.map((fk) => ({\n from: fk.from,\n table: fk.table,\n to: fk.to,\n })),\n indexes,\n });\n }\n\n if (parsed.format === \"json\") {\n console.log(\n JSON.stringify(\n { database: databaseLabel(url), tables: tableInfos },\n null,\n 2,\n ),\n );\n return;\n }\n\n // Human-readable output\n console.log(`Database: ${databaseLabel(url)}`);\n console.log(`Tables: ${tableInfos.length}\\n`);\n\n for (const table of tableInfos) {\n console.log(`Table: ${table.name} (${table.columns.length} columns)`);\n\n const fkMap = new Map<string, string>();\n for (const fk of table.foreignKeys) {\n fkMap.set(fk.from, `${fk.table}(${fk.to})`);\n }\n\n const nameWidth = Math.max(...table.columns.map((c) => c.name.length));\n const typeWidth = Math.max(...table.columns.map((c) => c.type.length));\n\n for (const col of table.columns) {\n const parts: string[] = [];\n if (col.pk) parts.push(\"PRIMARY KEY\");\n if (col.notnull && !col.pk) parts.push(\"NOT NULL\");\n if (col.dflt_value !== null) parts.push(`DEFAULT ${col.dflt_value}`);\n const fkRef = fkMap.get(col.name);\n if (fkRef) parts.push(`→ ${fkRef}`);\n\n const constraint = parts.length > 0 ? ` ${parts.join(\", \")}` : \"\";\n console.log(\n ` ${col.name.padEnd(nameWidth)} ${col.type.padEnd(typeWidth)}${constraint}`,\n );\n }\n\n if (table.indexes.length > 0) {\n console.log(` Indexes:`);\n for (const idx of table.indexes) {\n const unique = idx.unique ? \"UNIQUE \" : \"\";\n console.log(` ${unique}${idx.name} (${idx.columns.join(\", \")})`);\n }\n }\n\n console.log();\n }\n } finally {\n await sql.end();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Main entry\n// ---------------------------------------------------------------------------\n\nexport default async function dbSchema(args: string[]): Promise<void> {\n const parsed = parseArgs(args);\n\n if (parsed.help === \"true\") {\n console.log(`Usage: pnpm action db-schema [--db <path>] [--format json]\n\nOptions:\n --db <path> Path to SQLite database (default: data/app.db)\n --format json Output as JSON instead of human-readable text\n --help Show this help message`);\n return;\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 return introspectPostgres(url, parsed);\n }\n\n // SQLite / libsql path\n const client = await createSqliteScriptClient(url);\n\n try {\n const tablesResult = await client.execute(\n `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`,\n );\n const tables = tablesResult.rows.map((row) => ({\n name: row[0] as string,\n }));\n\n const tableInfos: TableInfo[] = [];\n\n for (const t of tables) {\n const escaped = t.name.replace(/\"/g, '\"\"');\n\n const columns = await pragma(client, `PRAGMA table_info(\"${escaped}\")`);\n const fks = await pragma(client, `PRAGMA foreign_key_list(\"${escaped}\")`);\n const idxList = await pragma(client, `PRAGMA index_list(\"${escaped}\")`);\n\n const indexes: { name: string; unique: boolean; columns: string[] }[] =\n [];\n for (const idx of idxList) {\n const idxName = idx.name as string;\n if (idxName.startsWith(\"sqlite_\")) continue;\n const idxInfo = await pragma(\n client,\n `PRAGMA index_info(\"${idxName.replace(/\"/g, '\"\"')}\")`,\n );\n indexes.push({\n name: idxName,\n unique: idx.unique === 1,\n columns: idxInfo.map((c) => c.name as string),\n });\n }\n\n tableInfos.push({\n name: t.name,\n columns: columns.map((c) => ({\n name: c.name as string,\n type: (c.type as string) || \"ANY\",\n notnull: c.notnull === 1,\n pk: c.pk === 1,\n dflt_value: c.dflt_value as string | null,\n })),\n foreignKeys: fks.map((fk) => ({\n from: fk.from as string,\n table: fk.table as string,\n to: fk.to as string,\n })),\n indexes,\n });\n }\n\n if (parsed.format === \"json\") {\n const dbLabel = databaseLabel(url);\n console.log(\n JSON.stringify({ database: dbLabel, tables: tableInfos }, null, 2),\n );\n return;\n }\n\n // Human-readable output\n const dbLabel = databaseLabel(url);\n console.log(`Database: ${dbLabel}`);\n console.log(`Tables: ${tableInfos.length}\\n`);\n\n for (const table of tableInfos) {\n console.log(`Table: ${table.name} (${table.columns.length} columns)`);\n\n // Build FK lookup for annotation\n const fkMap = new Map<string, string>();\n for (const fk of table.foreignKeys) {\n fkMap.set(fk.from, `${fk.table}(${fk.to})`);\n }\n\n // Find max widths for alignment\n const nameWidth = Math.max(...table.columns.map((c) => c.name.length));\n const typeWidth = Math.max(...table.columns.map((c) => c.type.length));\n\n for (const col of table.columns) {\n const parts: string[] = [];\n if (col.pk) parts.push(\"PRIMARY KEY\");\n if (col.notnull && !col.pk) parts.push(\"NOT NULL\");\n if (col.dflt_value !== null) parts.push(`DEFAULT ${col.dflt_value}`);\n const fkRef = fkMap.get(col.name);\n if (fkRef) parts.push(`→ ${fkRef}`);\n\n const constraint = parts.length > 0 ? ` ${parts.join(\", \")}` : \"\";\n console.log(\n ` ${col.name.padEnd(nameWidth)} ${col.type.padEnd(typeWidth)}${constraint}`,\n );\n }\n\n if (table.indexes.length > 0) {\n console.log(` Indexes:`);\n for (const idx of table.indexes) {\n const unique = idx.unique ? \"UNIQUE \" : \"\";\n console.log(` ${unique}${idx.name} (${idx.columns.join(\", \")})`);\n }\n }\n\n console.log();\n }\n } finally {\n client.close();\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SqliteScriptResult {
|
|
2
|
+
rows: any[];
|
|
3
|
+
columns: string[];
|
|
4
|
+
rowsAffected: number;
|
|
5
|
+
lastInsertRowid?: bigint | number;
|
|
6
|
+
}
|
|
7
|
+
export interface SqliteScriptClient {
|
|
8
|
+
execute(stmtOrSql: string | {
|
|
9
|
+
sql: string;
|
|
10
|
+
args?: any[];
|
|
11
|
+
}): Promise<SqliteScriptResult>;
|
|
12
|
+
close(): void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare function createSqliteScriptClient(url: string): Promise<SqliteScriptClient>;
|
|
15
|
+
//# sourceMappingURL=sqlite-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-client.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/sqlite-client.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CACL,SAAS,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;KAAE,GAChD,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/B,KAAK,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAcD,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,kBAAkB,CAAC,CA0C7B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getDatabaseAuthToken, isLocalSqliteUrl, prepareLocalSqliteUrl, sqliteFilenameFromUrl, } from "../../db/client.js";
|
|
2
|
+
function sqliteRowsToLibsqlShape(rows) {
|
|
3
|
+
const records = rows;
|
|
4
|
+
const columns = records.length > 0 ? Object.keys(records[0]) : [];
|
|
5
|
+
return {
|
|
6
|
+
rows: records.map((row) => {
|
|
7
|
+
const values = columns.map((column) => row[column]);
|
|
8
|
+
return Object.assign(values, row);
|
|
9
|
+
}),
|
|
10
|
+
columns,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export async function createSqliteScriptClient(url) {
|
|
14
|
+
if (isLocalSqliteUrl(url)) {
|
|
15
|
+
const sqliteUrl = await prepareLocalSqliteUrl(url.startsWith("file:") ? url : `file:${url}`);
|
|
16
|
+
const { default: Database } = await import("better-sqlite3");
|
|
17
|
+
const sqlite = new Database(sqliteFilenameFromUrl(sqliteUrl));
|
|
18
|
+
sqlite.pragma("busy_timeout = 10000");
|
|
19
|
+
sqlite.pragma("journal_mode = WAL");
|
|
20
|
+
return {
|
|
21
|
+
async execute(stmtOrSql) {
|
|
22
|
+
const sql = typeof stmtOrSql === "string" ? stmtOrSql : stmtOrSql.sql;
|
|
23
|
+
const args = typeof stmtOrSql === "string" ? [] : (stmtOrSql.args ?? []);
|
|
24
|
+
const stmt = sqlite.prepare(sql);
|
|
25
|
+
if (stmt.reader) {
|
|
26
|
+
return {
|
|
27
|
+
...sqliteRowsToLibsqlShape(stmt.all(...args)),
|
|
28
|
+
rowsAffected: 0,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const result = stmt.run(...args);
|
|
32
|
+
return {
|
|
33
|
+
rows: [],
|
|
34
|
+
columns: [],
|
|
35
|
+
rowsAffected: result.changes ?? 0,
|
|
36
|
+
lastInsertRowid: result.lastInsertRowid,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
close() {
|
|
40
|
+
sqlite.close();
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const { createClient } = await import("@libsql/client/web");
|
|
45
|
+
const client = createClient({
|
|
46
|
+
url,
|
|
47
|
+
authToken: getDatabaseAuthToken(),
|
|
48
|
+
});
|
|
49
|
+
return client;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=sqlite-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-client.js","sourceRoot":"","sources":["../../../src/scripts/db/sqlite-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAgB5B,SAAS,uBAAuB,CAAC,IAAe;IAC9C,MAAM,OAAO,GAAG,IAAiC,CAAC;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClE,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAU,CAAC;YAC7D,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACpC,CAAC,CAAC;QACF,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,GAAW;IAEX,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAC3C,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,EAAE,CAC9C,CAAC;QACF,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAEpC,OAAO;YACL,KAAK,CAAC,OAAO,CAAC,SAAS;gBACrB,MAAM,GAAG,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC;gBACtE,MAAM,IAAI,GACR,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;gBAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACjC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAChB,OAAO;wBACL,GAAG,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;wBAC7C,YAAY,EAAE,CAAC;qBAChB,CAAC;gBACJ,CAAC;gBACD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;gBACjC,OAAO;oBACL,IAAI,EAAE,EAAE;oBACR,OAAO,EAAE,EAAE;oBACX,YAAY,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC;oBACjC,eAAe,EAAE,MAAM,CAAC,eAAe;iBACxC,CAAC;YACJ,CAAC;YACD,KAAK;gBACH,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;SACF,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,GAAG;QACH,SAAS,EAAE,oBAAoB,EAAE;KAClC,CAAC,CAAC;IACH,OAAO,MAAuC,CAAC;AACjD,CAAC","sourcesContent":["import {\n getDatabaseAuthToken,\n isLocalSqliteUrl,\n prepareLocalSqliteUrl,\n sqliteFilenameFromUrl,\n} from \"../../db/client.js\";\n\nexport interface SqliteScriptResult {\n rows: any[];\n columns: string[];\n rowsAffected: number;\n lastInsertRowid?: bigint | number;\n}\n\nexport interface SqliteScriptClient {\n execute(\n stmtOrSql: string | { sql: string; args?: any[] },\n ): Promise<SqliteScriptResult>;\n close(): void | Promise<void>;\n}\n\nfunction sqliteRowsToLibsqlShape(rows: unknown[]) {\n const records = rows as Record<string, unknown>[];\n const columns = records.length > 0 ? Object.keys(records[0]) : [];\n return {\n rows: records.map((row) => {\n const values = columns.map((column) => row[column]) as any[];\n return Object.assign(values, row);\n }),\n columns,\n };\n}\n\nexport async function createSqliteScriptClient(\n url: string,\n): Promise<SqliteScriptClient> {\n if (isLocalSqliteUrl(url)) {\n const sqliteUrl = await prepareLocalSqliteUrl(\n url.startsWith(\"file:\") ? url : `file:${url}`,\n );\n const { default: Database } = await import(\"better-sqlite3\");\n const sqlite = new Database(sqliteFilenameFromUrl(sqliteUrl));\n sqlite.pragma(\"busy_timeout = 10000\");\n sqlite.pragma(\"journal_mode = WAL\");\n\n return {\n async execute(stmtOrSql) {\n const sql = typeof stmtOrSql === \"string\" ? stmtOrSql : stmtOrSql.sql;\n const args =\n typeof stmtOrSql === \"string\" ? [] : (stmtOrSql.args ?? []);\n const stmt = sqlite.prepare(sql);\n if (stmt.reader) {\n return {\n ...sqliteRowsToLibsqlShape(stmt.all(...args)),\n rowsAffected: 0,\n };\n }\n const result = stmt.run(...args);\n return {\n rows: [],\n columns: [],\n rowsAffected: result.changes ?? 0,\n lastInsertRowid: result.lastInsertRowid,\n };\n },\n close() {\n sqlite.close();\n },\n };\n }\n\n const { createClient } = await import(\"@libsql/client/web\");\n const client = createClient({\n url,\n authToken: getDatabaseAuthToken(),\n });\n return client as unknown as SqliteScriptClient;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAsChE,KAAK,KAAK,GAAG,SAAS,CAAC;AAQvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AA6BlE;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAMD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF;;;OAGG;IACH,kBAAkB,CAAC,EAAE;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF;;OAEG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAqBD,eAAO,MAAM,WAAW,QAER,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/server/auth.js
CHANGED
|
@@ -82,6 +82,37 @@ function getOAuthStateAppId() {
|
|
|
82
82
|
.replace(/^-+|-+$/g, "");
|
|
83
83
|
return slug || undefined;
|
|
84
84
|
}
|
|
85
|
+
function oauthDebugFlowId(flowId) {
|
|
86
|
+
return typeof flowId === "string" && flowId ? flowId.slice(-10) : undefined;
|
|
87
|
+
}
|
|
88
|
+
function oauthDebugUrlPath(value) {
|
|
89
|
+
if (typeof value !== "string" || !value)
|
|
90
|
+
return undefined;
|
|
91
|
+
try {
|
|
92
|
+
const url = new URL(value);
|
|
93
|
+
return url.pathname;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function logGoogleOAuthDebug(event, phase, details = {}) {
|
|
100
|
+
const { flowId, ...rest } = details;
|
|
101
|
+
const reqUrl = event.node?.req?.url ?? event.path ?? "";
|
|
102
|
+
const path = reqUrl.split("?")[0] || undefined;
|
|
103
|
+
const userAgent = getHeader(event, "user-agent") || "";
|
|
104
|
+
const referer = getHeader(event, "referer") || "";
|
|
105
|
+
console.info("[agent-native][google-oauth]", {
|
|
106
|
+
phase,
|
|
107
|
+
app: getOAuthStateAppId(),
|
|
108
|
+
path,
|
|
109
|
+
flow: oauthDebugFlowId(flowId),
|
|
110
|
+
electron: /Electron/i.test(userAgent),
|
|
111
|
+
agentNativeDesktop: /AgentNativeDesktop/i.test(userAgent),
|
|
112
|
+
builderReferrer: /builder\.(io|my)|builderio\.xyz/i.test(referer),
|
|
113
|
+
...rest,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
85
116
|
const DEFAULT_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
|
|
86
117
|
// ---------------------------------------------------------------------------
|
|
87
118
|
// Environment helpers
|
|
@@ -1332,6 +1363,15 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1332
1363
|
returnUrl,
|
|
1333
1364
|
flowId,
|
|
1334
1365
|
});
|
|
1366
|
+
logGoogleOAuthDebug(event, "auth-url", {
|
|
1367
|
+
flowId,
|
|
1368
|
+
desktop,
|
|
1369
|
+
redirectPath: oauthDebugUrlPath(redirectUri),
|
|
1370
|
+
returnUrl,
|
|
1371
|
+
redirect: q.redirect === "1",
|
|
1372
|
+
workspace: process.env.AGENT_NATIVE_WORKSPACE === "1" ||
|
|
1373
|
+
process.env.VITE_AGENT_NATIVE_WORKSPACE === "1",
|
|
1374
|
+
});
|
|
1335
1375
|
const params = new URLSearchParams({
|
|
1336
1376
|
client_id: process.env.GOOGLE_CLIENT_ID,
|
|
1337
1377
|
redirect_uri: redirectUri,
|
|
@@ -1357,6 +1397,8 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1357
1397
|
const callbackRelay = workspaceOAuthCallbackRelayResponse(event);
|
|
1358
1398
|
if (callbackRelay)
|
|
1359
1399
|
return callbackRelay;
|
|
1400
|
+
let callbackFlowId;
|
|
1401
|
+
let callbackDesktop = false;
|
|
1360
1402
|
try {
|
|
1361
1403
|
const query = getQuery(event);
|
|
1362
1404
|
const code = query.code;
|
|
@@ -1365,6 +1407,15 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1365
1407
|
return { error: "Missing authorization code" };
|
|
1366
1408
|
}
|
|
1367
1409
|
const { redirectUri, desktop, returnUrl, flowId } = decodeOAuthState(query.state, getAppUrl(event, "/_agent-native/google/callback"));
|
|
1410
|
+
callbackFlowId = flowId;
|
|
1411
|
+
callbackDesktop = desktop;
|
|
1412
|
+
logGoogleOAuthDebug(event, "callback-start", {
|
|
1413
|
+
flowId,
|
|
1414
|
+
desktop,
|
|
1415
|
+
redirectPath: oauthDebugUrlPath(redirectUri),
|
|
1416
|
+
hasCode: !!code,
|
|
1417
|
+
returnUrl,
|
|
1418
|
+
});
|
|
1368
1419
|
// Defence in depth: the state is HMAC-signed, but if the signing
|
|
1369
1420
|
// key ever leaked an attacker could mint state with their own
|
|
1370
1421
|
// redirect_uri. Re-validate against the same allowlist used at
|
|
@@ -1413,6 +1464,12 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1413
1464
|
hasProductionSession: false,
|
|
1414
1465
|
desktop,
|
|
1415
1466
|
});
|
|
1467
|
+
logGoogleOAuthDebug(event, "callback-session-created", {
|
|
1468
|
+
flowId,
|
|
1469
|
+
desktop,
|
|
1470
|
+
hasSessionToken: !!sessionToken,
|
|
1471
|
+
emailDomain: email.split("@")[1] || "",
|
|
1472
|
+
});
|
|
1416
1473
|
if (flowId && sessionToken) {
|
|
1417
1474
|
_desktopExchanges.set(flowId, {
|
|
1418
1475
|
token: sessionToken,
|
|
@@ -1423,6 +1480,10 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1423
1480
|
// Workers, multi-region). Fire-and-forget — in-memory Map is
|
|
1424
1481
|
// still the primary fast path for same-instance requests.
|
|
1425
1482
|
void persistDesktopExchangeToDB(flowId, sessionToken, email);
|
|
1483
|
+
logGoogleOAuthDebug(event, "callback-exchange-stored", {
|
|
1484
|
+
flowId,
|
|
1485
|
+
desktop,
|
|
1486
|
+
});
|
|
1426
1487
|
}
|
|
1427
1488
|
return oauthCallbackResponse(event, email, {
|
|
1428
1489
|
sessionToken,
|
|
@@ -1433,6 +1494,11 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1433
1494
|
}
|
|
1434
1495
|
catch (error) {
|
|
1435
1496
|
const msg = error.message || "Unknown error";
|
|
1497
|
+
logGoogleOAuthDebug(event, "callback-error", {
|
|
1498
|
+
flowId: callbackFlowId,
|
|
1499
|
+
desktop: callbackDesktop,
|
|
1500
|
+
message: msg,
|
|
1501
|
+
});
|
|
1436
1502
|
return oauthErrorPage(`Connection failed: ${msg}`);
|
|
1437
1503
|
}
|
|
1438
1504
|
}));
|
|
@@ -1445,7 +1511,8 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1445
1511
|
setResponseStatus(event, 405);
|
|
1446
1512
|
return { error: "Method not allowed" };
|
|
1447
1513
|
}
|
|
1448
|
-
const
|
|
1514
|
+
const query = getQuery(event);
|
|
1515
|
+
const flowId = query.flow_id;
|
|
1449
1516
|
if (!flowId) {
|
|
1450
1517
|
setResponseStatus(event, 400);
|
|
1451
1518
|
return { error: "Missing flow_id" };
|
|
@@ -1457,7 +1524,12 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1457
1524
|
// OAuth callback and the polling request may hit different isolates.
|
|
1458
1525
|
const fromDb = await consumeDesktopExchangeFromDB(flowId);
|
|
1459
1526
|
if (!fromDb) {
|
|
1460
|
-
|
|
1527
|
+
// Don't log on the pending path — clients poll every second for up
|
|
1528
|
+
// to 5 minutes, so logging here floods telemetry. The auth-url,
|
|
1529
|
+
// callback-start, callback-session-created, exchange-success, and
|
|
1530
|
+
// exchange-error breadcrumbs already cover every meaningful state
|
|
1531
|
+
// transition.
|
|
1532
|
+
return { pending: true, flow: oauthDebugFlowId(flowId) };
|
|
1461
1533
|
}
|
|
1462
1534
|
entry =
|
|
1463
1535
|
"error" in fromDb
|
|
@@ -1473,6 +1545,11 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1473
1545
|
// DB fallback path after in-memory consumption.
|
|
1474
1546
|
void removeSession(`dex:${flowId}`);
|
|
1475
1547
|
if ("error" in entry) {
|
|
1548
|
+
logGoogleOAuthDebug(event, "exchange-error", {
|
|
1549
|
+
flowId,
|
|
1550
|
+
message: entry.error.message,
|
|
1551
|
+
code: entry.error.code,
|
|
1552
|
+
});
|
|
1476
1553
|
return { error: entry.error.message, ...entry.error };
|
|
1477
1554
|
}
|
|
1478
1555
|
// Make the exchange itself establish the app session. Older clients
|
|
@@ -1480,6 +1557,10 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
1480
1557
|
// OAuth handoff should not depend on that second request succeeding.
|
|
1481
1558
|
setFrameworkSessionCookie(event, entry.token);
|
|
1482
1559
|
setResponseHeader(event, "Referrer-Policy", "no-referrer");
|
|
1560
|
+
logGoogleOAuthDebug(event, "exchange-success", {
|
|
1561
|
+
flowId,
|
|
1562
|
+
emailDomain: entry.email.split("@")[1] || "",
|
|
1563
|
+
});
|
|
1483
1564
|
return { token: entry.token, email: entry.email };
|
|
1484
1565
|
}));
|
|
1485
1566
|
const accessTokens = getAccessTokens();
|