@agent-native/core 0.162.0 → 0.163.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/analytics/server/plugins/collab.ts +1 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/clips/app/lib/camera-composite.ts +15 -1
- package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-crashes-when-a-camera-bubble-starts-at-a-tin.md +6 -0
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/content/actions/create-content-database.ts +1 -1
- package/corpus/templates/content/actions/create-document.ts +1 -1
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +6 -1
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/DEVELOPING.md +17 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +67 -0
- package/corpus/templates/slides/actions/request-deck-access.ts +569 -0
- package/corpus/templates/slides/agent-native.json +3 -0
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +1 -1
- package/corpus/templates/slides/app/components/layout/Header.tsx +2 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +51 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +12 -0
- package/corpus/templates/slides/app/lib/deck-editor-loading.ts +7 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +173 -33
- package/corpus/templates/slides/changelog/2026-08-18-private-deck-links-now-explain-access-and-let-viewers-notify.md +6 -0
- package/corpus/templates/slides/server/db/schema.ts +10 -0
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +1 -0
- package/corpus/templates/slides/server/plugins/db.ts +17 -0
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/app-config/schema.d.ts +1 -0
- package/dist/app-config/workspace.d.ts +1 -0
- package/dist/app-config/workspace.js +8 -0
- package/dist/chat-threads/schema.d.ts +2 -2
- package/dist/client/analytics.d.ts +1 -0
- package/dist/client/analytics.js +19 -5
- package/dist/client/org/TeamPage.js +15 -2
- package/dist/client/org/hooks.d.ts +2 -0
- package/dist/client/org/hooks.js +12 -0
- package/dist/client/org/index.d.ts +2 -2
- package/dist/client/org/index.js +1 -1
- package/dist/client/sharing/ShareButton.js +43 -18
- package/dist/client/sharing/useShareButtonController.d.ts +12 -2
- package/dist/client/sharing/useShareButtonController.js +38 -8
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +2 -0
- package/dist/collab/storage.js +7 -0
- package/dist/config.js +11 -1
- package/dist/dashboard-storage/schema.d.ts +2 -2
- package/dist/data-programs/schema.d.ts +2 -2
- package/dist/deploy/build.d.ts +1 -1
- package/dist/deploy/build.js +89 -12
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/extensions/store.js +3 -0
- package/dist/localization/core-messages/ar-SA.js +1 -0
- package/dist/localization/core-messages/de-DE.js +1 -0
- package/dist/localization/core-messages/en-US.d.ts +1 -0
- package/dist/localization/core-messages/en-US.js +1 -0
- package/dist/localization/core-messages/es-ES.js +1 -0
- package/dist/localization/core-messages/fr-FR.js +1 -0
- package/dist/localization/core-messages/hi-IN.js +1 -0
- package/dist/localization/core-messages/ja-JP.js +1 -0
- package/dist/localization/core-messages/ko-KR.js +1 -0
- package/dist/localization/core-messages/pt-BR.js +1 -0
- package/dist/localization/core-messages/zh-CN.js +1 -0
- package/dist/localization/core-messages/zh-TW.js +1 -0
- package/dist/localization/core-messages.d.ts +1 -0
- package/dist/localization/default-messages.d.ts +4 -0
- package/dist/localization/default-messages.js +4 -0
- package/dist/observability/routes.d.ts +1 -1
- package/dist/observability/tracking-identity.js +2 -0
- package/dist/org/handlers.d.ts +6 -1
- package/dist/org/handlers.js +43 -0
- package/dist/org/index.d.ts +3 -3
- package/dist/org/index.js +2 -2
- package/dist/org/migrations.js +33 -0
- package/dist/org/plugin.js +10 -1
- package/dist/org/schema.d.ts +315 -0
- package/dist/org/schema.js +20 -1
- package/dist/org/types.d.ts +3 -0
- package/dist/org/workspace-app-access.d.ts +10 -0
- package/dist/org/workspace-app-access.js +179 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +14 -1
- package/dist/server/collab-plugin.d.ts +6 -0
- package/dist/server/collab-plugin.js +27 -6
- package/dist/server/deploy-environment.d.ts +1 -1
- package/dist/server/deploy-environment.js +40 -2
- package/dist/server/poll.js +6 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/sentry-config.js +8 -4
- package/dist/server/sentry.js +4 -0
- package/dist/sharing/access.d.ts +2 -2
- package/dist/sharing/access.js +56 -3
- package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
- package/dist/sharing/actions/list-resource-shares.js +26 -1
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/actions/share-resource.js +23 -4
- package/dist/sharing/actions/unshare-resource.d.ts +1 -1
- package/dist/sharing/actions/unshare-resource.js +1 -1
- package/dist/sharing/registry.d.ts +12 -0
- package/dist/sharing/schema.d.ts +4 -4
- package/dist/sharing/schema.js +2 -2
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/tracking/registry.js +8 -6
- package/dist/vite/client.js +5 -0
- package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +9 -1
- package/dist/workspace-connections/actions/list-workspace-user-groups.js +9 -4
- package/dist/workspace-connections/groups.d.ts +2 -0
- package/dist/workspace-connections/groups.js +16 -5
- package/docs/content/deployment.mdx +19 -5
- package/package.json +1 -1
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
package/dist/org/schema.d.ts
CHANGED
|
@@ -536,3 +536,318 @@ export declare const orgInvitations: import("drizzle-orm/sqlite-core").SQLiteTab
|
|
|
536
536
|
};
|
|
537
537
|
dialect: 'sqlite';
|
|
538
538
|
}>;
|
|
539
|
+
/** Workspace app access is framework-owned so every mounted app can enforce it. */
|
|
540
|
+
export declare const workspaceApps: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
541
|
+
name: "workspace_apps";
|
|
542
|
+
schema: undefined;
|
|
543
|
+
columns: {
|
|
544
|
+
ownerEmail: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
545
|
+
name: "owner_email";
|
|
546
|
+
tableName: "workspace_apps";
|
|
547
|
+
dataType: "string";
|
|
548
|
+
columnType: "SQLiteText";
|
|
549
|
+
data: string;
|
|
550
|
+
driverParam: string;
|
|
551
|
+
notNull: true;
|
|
552
|
+
hasDefault: true;
|
|
553
|
+
isPrimaryKey: false;
|
|
554
|
+
isAutoincrement: false;
|
|
555
|
+
hasRuntimeDefault: false;
|
|
556
|
+
enumValues: [string, ...string[]];
|
|
557
|
+
baseColumn: never;
|
|
558
|
+
identity: undefined;
|
|
559
|
+
generated: undefined;
|
|
560
|
+
}, {}, {
|
|
561
|
+
length: number;
|
|
562
|
+
}>;
|
|
563
|
+
orgId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
564
|
+
name: "org_id";
|
|
565
|
+
tableName: "workspace_apps";
|
|
566
|
+
dataType: "string";
|
|
567
|
+
columnType: "SQLiteText";
|
|
568
|
+
data: string;
|
|
569
|
+
driverParam: string;
|
|
570
|
+
notNull: false;
|
|
571
|
+
hasDefault: false;
|
|
572
|
+
isPrimaryKey: false;
|
|
573
|
+
isAutoincrement: false;
|
|
574
|
+
hasRuntimeDefault: false;
|
|
575
|
+
enumValues: [string, ...string[]];
|
|
576
|
+
baseColumn: never;
|
|
577
|
+
identity: undefined;
|
|
578
|
+
generated: undefined;
|
|
579
|
+
}, {}, {
|
|
580
|
+
length: number;
|
|
581
|
+
}>;
|
|
582
|
+
id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
583
|
+
name: "id";
|
|
584
|
+
tableName: "workspace_apps";
|
|
585
|
+
dataType: "string";
|
|
586
|
+
columnType: "SQLiteText";
|
|
587
|
+
data: string;
|
|
588
|
+
driverParam: string;
|
|
589
|
+
notNull: true;
|
|
590
|
+
hasDefault: false;
|
|
591
|
+
isPrimaryKey: true;
|
|
592
|
+
isAutoincrement: false;
|
|
593
|
+
hasRuntimeDefault: false;
|
|
594
|
+
enumValues: [string, ...string[]];
|
|
595
|
+
baseColumn: never;
|
|
596
|
+
identity: undefined;
|
|
597
|
+
generated: undefined;
|
|
598
|
+
}, {}, {
|
|
599
|
+
length: number;
|
|
600
|
+
}>;
|
|
601
|
+
visibility: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
602
|
+
name: "visibility";
|
|
603
|
+
tableName: "workspace_apps";
|
|
604
|
+
dataType: "string";
|
|
605
|
+
columnType: "SQLiteText";
|
|
606
|
+
data: "org" | "private" | "public";
|
|
607
|
+
driverParam: string;
|
|
608
|
+
notNull: true;
|
|
609
|
+
hasDefault: true;
|
|
610
|
+
isPrimaryKey: false;
|
|
611
|
+
isAutoincrement: false;
|
|
612
|
+
hasRuntimeDefault: false;
|
|
613
|
+
enumValues: ["private", "org", "public"];
|
|
614
|
+
baseColumn: never;
|
|
615
|
+
identity: undefined;
|
|
616
|
+
generated: undefined;
|
|
617
|
+
}, {}, {
|
|
618
|
+
length: number;
|
|
619
|
+
}>;
|
|
620
|
+
name: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
621
|
+
name: "name";
|
|
622
|
+
tableName: "workspace_apps";
|
|
623
|
+
dataType: "string";
|
|
624
|
+
columnType: "SQLiteText";
|
|
625
|
+
data: string;
|
|
626
|
+
driverParam: string;
|
|
627
|
+
notNull: true;
|
|
628
|
+
hasDefault: false;
|
|
629
|
+
isPrimaryKey: false;
|
|
630
|
+
isAutoincrement: false;
|
|
631
|
+
hasRuntimeDefault: false;
|
|
632
|
+
enumValues: [string, ...string[]];
|
|
633
|
+
baseColumn: never;
|
|
634
|
+
identity: undefined;
|
|
635
|
+
generated: undefined;
|
|
636
|
+
}, {}, {
|
|
637
|
+
length: number;
|
|
638
|
+
}>;
|
|
639
|
+
description: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
640
|
+
name: "description";
|
|
641
|
+
tableName: "workspace_apps";
|
|
642
|
+
dataType: "string";
|
|
643
|
+
columnType: "SQLiteText";
|
|
644
|
+
data: string;
|
|
645
|
+
driverParam: string;
|
|
646
|
+
notNull: false;
|
|
647
|
+
hasDefault: false;
|
|
648
|
+
isPrimaryKey: false;
|
|
649
|
+
isAutoincrement: false;
|
|
650
|
+
hasRuntimeDefault: false;
|
|
651
|
+
enumValues: [string, ...string[]];
|
|
652
|
+
baseColumn: never;
|
|
653
|
+
identity: undefined;
|
|
654
|
+
generated: undefined;
|
|
655
|
+
}, {}, {
|
|
656
|
+
length: number;
|
|
657
|
+
}>;
|
|
658
|
+
path: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
659
|
+
name: "path";
|
|
660
|
+
tableName: "workspace_apps";
|
|
661
|
+
dataType: "string";
|
|
662
|
+
columnType: "SQLiteText";
|
|
663
|
+
data: string;
|
|
664
|
+
driverParam: string;
|
|
665
|
+
notNull: true;
|
|
666
|
+
hasDefault: false;
|
|
667
|
+
isPrimaryKey: false;
|
|
668
|
+
isAutoincrement: false;
|
|
669
|
+
hasRuntimeDefault: false;
|
|
670
|
+
enumValues: [string, ...string[]];
|
|
671
|
+
baseColumn: never;
|
|
672
|
+
identity: undefined;
|
|
673
|
+
generated: undefined;
|
|
674
|
+
}, {}, {
|
|
675
|
+
length: number;
|
|
676
|
+
}>;
|
|
677
|
+
createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
678
|
+
name: "created_at";
|
|
679
|
+
tableName: "workspace_apps";
|
|
680
|
+
dataType: "number";
|
|
681
|
+
columnType: "SQLiteInteger";
|
|
682
|
+
data: number;
|
|
683
|
+
driverParam: number;
|
|
684
|
+
notNull: true;
|
|
685
|
+
hasDefault: false;
|
|
686
|
+
isPrimaryKey: false;
|
|
687
|
+
isAutoincrement: false;
|
|
688
|
+
hasRuntimeDefault: false;
|
|
689
|
+
enumValues: undefined;
|
|
690
|
+
baseColumn: never;
|
|
691
|
+
identity: undefined;
|
|
692
|
+
generated: undefined;
|
|
693
|
+
}, {}, {}>;
|
|
694
|
+
updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
695
|
+
name: "updated_at";
|
|
696
|
+
tableName: "workspace_apps";
|
|
697
|
+
dataType: "number";
|
|
698
|
+
columnType: "SQLiteInteger";
|
|
699
|
+
data: number;
|
|
700
|
+
driverParam: number;
|
|
701
|
+
notNull: true;
|
|
702
|
+
hasDefault: false;
|
|
703
|
+
isPrimaryKey: false;
|
|
704
|
+
isAutoincrement: false;
|
|
705
|
+
hasRuntimeDefault: false;
|
|
706
|
+
enumValues: undefined;
|
|
707
|
+
baseColumn: never;
|
|
708
|
+
identity: undefined;
|
|
709
|
+
generated: undefined;
|
|
710
|
+
}, {}, {}>;
|
|
711
|
+
};
|
|
712
|
+
dialect: 'sqlite';
|
|
713
|
+
}>;
|
|
714
|
+
export declare const workspaceAppShares: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
715
|
+
name: string;
|
|
716
|
+
schema: undefined;
|
|
717
|
+
columns: {
|
|
718
|
+
id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
719
|
+
name: "id";
|
|
720
|
+
tableName: string;
|
|
721
|
+
dataType: "string";
|
|
722
|
+
columnType: "SQLiteText";
|
|
723
|
+
data: string;
|
|
724
|
+
driverParam: string;
|
|
725
|
+
notNull: true;
|
|
726
|
+
hasDefault: false;
|
|
727
|
+
isPrimaryKey: true;
|
|
728
|
+
isAutoincrement: false;
|
|
729
|
+
hasRuntimeDefault: false;
|
|
730
|
+
enumValues: [string, ...string[]];
|
|
731
|
+
baseColumn: never;
|
|
732
|
+
identity: undefined;
|
|
733
|
+
generated: undefined;
|
|
734
|
+
}, {}, {
|
|
735
|
+
length: number;
|
|
736
|
+
}>;
|
|
737
|
+
resourceId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
738
|
+
name: "resource_id";
|
|
739
|
+
tableName: string;
|
|
740
|
+
dataType: "string";
|
|
741
|
+
columnType: "SQLiteText";
|
|
742
|
+
data: string;
|
|
743
|
+
driverParam: string;
|
|
744
|
+
notNull: true;
|
|
745
|
+
hasDefault: false;
|
|
746
|
+
isPrimaryKey: false;
|
|
747
|
+
isAutoincrement: false;
|
|
748
|
+
hasRuntimeDefault: false;
|
|
749
|
+
enumValues: [string, ...string[]];
|
|
750
|
+
baseColumn: never;
|
|
751
|
+
identity: undefined;
|
|
752
|
+
generated: undefined;
|
|
753
|
+
}, {}, {
|
|
754
|
+
length: number;
|
|
755
|
+
}>;
|
|
756
|
+
principalType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
757
|
+
name: "principal_type";
|
|
758
|
+
tableName: string;
|
|
759
|
+
dataType: "string";
|
|
760
|
+
columnType: "SQLiteText";
|
|
761
|
+
data: "group" | "org" | "user";
|
|
762
|
+
driverParam: string;
|
|
763
|
+
notNull: true;
|
|
764
|
+
hasDefault: false;
|
|
765
|
+
isPrimaryKey: false;
|
|
766
|
+
isAutoincrement: false;
|
|
767
|
+
hasRuntimeDefault: false;
|
|
768
|
+
enumValues: ["user", "group", "org"];
|
|
769
|
+
baseColumn: never;
|
|
770
|
+
identity: undefined;
|
|
771
|
+
generated: undefined;
|
|
772
|
+
}, {}, {
|
|
773
|
+
length: number;
|
|
774
|
+
}>;
|
|
775
|
+
principalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
776
|
+
name: "principal_id";
|
|
777
|
+
tableName: string;
|
|
778
|
+
dataType: "string";
|
|
779
|
+
columnType: "SQLiteText";
|
|
780
|
+
data: string;
|
|
781
|
+
driverParam: string;
|
|
782
|
+
notNull: true;
|
|
783
|
+
hasDefault: false;
|
|
784
|
+
isPrimaryKey: false;
|
|
785
|
+
isAutoincrement: false;
|
|
786
|
+
hasRuntimeDefault: false;
|
|
787
|
+
enumValues: [string, ...string[]];
|
|
788
|
+
baseColumn: never;
|
|
789
|
+
identity: undefined;
|
|
790
|
+
generated: undefined;
|
|
791
|
+
}, {}, {
|
|
792
|
+
length: number;
|
|
793
|
+
}>;
|
|
794
|
+
role: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
795
|
+
name: "role";
|
|
796
|
+
tableName: string;
|
|
797
|
+
dataType: "string";
|
|
798
|
+
columnType: "SQLiteText";
|
|
799
|
+
data: "admin" | "commenter" | "editor" | "viewer";
|
|
800
|
+
driverParam: string;
|
|
801
|
+
notNull: true;
|
|
802
|
+
hasDefault: true;
|
|
803
|
+
isPrimaryKey: false;
|
|
804
|
+
isAutoincrement: false;
|
|
805
|
+
hasRuntimeDefault: false;
|
|
806
|
+
enumValues: ["viewer", "commenter", "editor", "admin"];
|
|
807
|
+
baseColumn: never;
|
|
808
|
+
identity: undefined;
|
|
809
|
+
generated: undefined;
|
|
810
|
+
}, {}, {
|
|
811
|
+
length: number;
|
|
812
|
+
}>;
|
|
813
|
+
createdBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
814
|
+
name: "created_by";
|
|
815
|
+
tableName: string;
|
|
816
|
+
dataType: "string";
|
|
817
|
+
columnType: "SQLiteText";
|
|
818
|
+
data: string;
|
|
819
|
+
driverParam: string;
|
|
820
|
+
notNull: true;
|
|
821
|
+
hasDefault: true;
|
|
822
|
+
isPrimaryKey: false;
|
|
823
|
+
isAutoincrement: false;
|
|
824
|
+
hasRuntimeDefault: false;
|
|
825
|
+
enumValues: [string, ...string[]];
|
|
826
|
+
baseColumn: never;
|
|
827
|
+
identity: undefined;
|
|
828
|
+
generated: undefined;
|
|
829
|
+
}, {}, {
|
|
830
|
+
length: number;
|
|
831
|
+
}>;
|
|
832
|
+
createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
833
|
+
name: "created_at";
|
|
834
|
+
tableName: string;
|
|
835
|
+
dataType: "string";
|
|
836
|
+
columnType: "SQLiteText";
|
|
837
|
+
data: string;
|
|
838
|
+
driverParam: string;
|
|
839
|
+
notNull: true;
|
|
840
|
+
hasDefault: true;
|
|
841
|
+
isPrimaryKey: false;
|
|
842
|
+
isAutoincrement: false;
|
|
843
|
+
hasRuntimeDefault: false;
|
|
844
|
+
enumValues: [string, ...string[]];
|
|
845
|
+
baseColumn: never;
|
|
846
|
+
identity: undefined;
|
|
847
|
+
generated: undefined;
|
|
848
|
+
}, {}, {
|
|
849
|
+
length: number;
|
|
850
|
+
}>;
|
|
851
|
+
};
|
|
852
|
+
dialect: 'sqlite';
|
|
853
|
+
}>;
|
package/dist/org/schema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { table, text, integer } from "../db/schema.js";
|
|
1
|
+
import { table, text, integer, ownableColumns, createSharesTable, } from "../db/schema.js";
|
|
2
2
|
export const organizations = table("organizations", {
|
|
3
3
|
id: text("id").primaryKey(),
|
|
4
4
|
name: text("name").notNull(),
|
|
@@ -39,3 +39,22 @@ export const orgInvitations = table("org_invitations", {
|
|
|
39
39
|
status: text("status").notNull(),
|
|
40
40
|
role: text("role"),
|
|
41
41
|
});
|
|
42
|
+
/** Workspace app access is framework-owned so every mounted app can enforce it. */
|
|
43
|
+
export const workspaceApps = table("workspace_apps", {
|
|
44
|
+
id: text("id").primaryKey(),
|
|
45
|
+
...ownableColumns(),
|
|
46
|
+
// Workspace apps are visible to their organization by default. The generic
|
|
47
|
+
// ownable primitive remains private-by-default for user-created resources;
|
|
48
|
+
// app creation is a deliberate workspace-level exception.
|
|
49
|
+
visibility: text("visibility", {
|
|
50
|
+
enum: ["private", "org", "public"],
|
|
51
|
+
})
|
|
52
|
+
.notNull()
|
|
53
|
+
.default("org"),
|
|
54
|
+
name: text("name").notNull(),
|
|
55
|
+
description: text("description"),
|
|
56
|
+
path: text("path").notNull(),
|
|
57
|
+
createdAt: integer("created_at").notNull(),
|
|
58
|
+
updatedAt: integer("updated_at").notNull(),
|
|
59
|
+
});
|
|
60
|
+
export const workspaceAppShares = createSharesTable("workspace_app_shares");
|
package/dist/org/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type OrgRole = "owner" | "admin" | "member";
|
|
5
5
|
export type RequiredAuthProvider = "google" | null;
|
|
6
|
+
export type WorkspaceAppDefaultVisibility = "private" | "org";
|
|
6
7
|
export interface OrgContext {
|
|
7
8
|
email: string;
|
|
8
9
|
orgId: string | null;
|
|
@@ -43,6 +44,8 @@ export interface OrgInfo {
|
|
|
43
44
|
workspaceUrl: string | null;
|
|
44
45
|
/** Sign-in provider required for members of the active org. */
|
|
45
46
|
requiredAuthProvider: RequiredAuthProvider;
|
|
47
|
+
/** Default visibility applied when a new workspace app is first registered. */
|
|
48
|
+
workspaceAppDefaultVisibility?: WorkspaceAppDefaultVisibility;
|
|
46
49
|
/**
|
|
47
50
|
* Whether the active org has an A2A secret. The value itself is never part
|
|
48
51
|
* of this payload — owners/admins fetch it on demand from
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface WorkspaceAppAccessContext {
|
|
2
|
+
email: string;
|
|
3
|
+
orgId?: string | null;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Enforce the workspace-app ACL before a hosted app's authenticated API
|
|
7
|
+
* surface is reached. The app shell remains cacheable and anonymous; this
|
|
8
|
+
* check protects the session-backed APIs/actions that make the app useful.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isWorkspaceAppAccessAllowed(appId: string, context: WorkspaceAppAccessContext): Promise<boolean>;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { signA2AToken } from "../a2a/client.js";
|
|
2
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
3
|
+
import { getDbExec } from "../db/client.js";
|
|
4
|
+
import { workspaceUserGroupsIncludeUser } from "../workspace-connections/groups.js";
|
|
5
|
+
import { getOrgA2ASecret, getOrgDomain } from "./context.js";
|
|
6
|
+
const WORKSPACE_APPS_ACTION_PATH = "/_agent-native/actions/list-workspace-apps";
|
|
7
|
+
const WORKSPACE_APP_ACCESS_TIMEOUT_MS = 2_500;
|
|
8
|
+
function normalizedEmail(email) {
|
|
9
|
+
return email.trim().toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
function configuredWorkspaceDirectory() {
|
|
12
|
+
const workspace = getAppConfig().workspace;
|
|
13
|
+
return (workspace.orgDirectoryUrl?.trim() || workspace.gatewayUrl?.trim() || null);
|
|
14
|
+
}
|
|
15
|
+
function workspaceAppsActionUrl(base) {
|
|
16
|
+
try {
|
|
17
|
+
const baseUrl = new URL(base);
|
|
18
|
+
if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const basePath = baseUrl.pathname.replace(/\/+$/, "");
|
|
22
|
+
baseUrl.pathname = `${basePath}${WORKSPACE_APPS_ACTION_PATH}`;
|
|
23
|
+
baseUrl.search = "";
|
|
24
|
+
baseUrl.searchParams.set("includeAgentCards", "false");
|
|
25
|
+
baseUrl.searchParams.set("audience", "all");
|
|
26
|
+
baseUrl.hash = "";
|
|
27
|
+
return baseUrl;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// coercion-ok: malformed configured URL is a typed unavailable registry.
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function workspaceAppsFromResponse(value) {
|
|
35
|
+
if (Array.isArray(value))
|
|
36
|
+
return value;
|
|
37
|
+
if (value &&
|
|
38
|
+
typeof value === "object" &&
|
|
39
|
+
Array.isArray(value.apps)) {
|
|
40
|
+
return value.apps;
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Hosted app databases are not the authority for workspace-app rows. Ask the
|
|
46
|
+
* Dispatch registry action, which resolves the ACL against its shared store,
|
|
47
|
+
* so an app-scoped database cannot accidentally turn a missing local row into
|
|
48
|
+
* access. A configured registry is fail-closed on every network/auth error.
|
|
49
|
+
*/
|
|
50
|
+
async function hostedWorkspaceAppAccess(appId, context, email) {
|
|
51
|
+
const configuredDirectory = configuredWorkspaceDirectory();
|
|
52
|
+
if (!configuredDirectory)
|
|
53
|
+
return null;
|
|
54
|
+
const url = workspaceAppsActionUrl(configuredDirectory);
|
|
55
|
+
if (!url)
|
|
56
|
+
return false;
|
|
57
|
+
const orgId = context.orgId?.trim() || null;
|
|
58
|
+
const [orgDomain, orgSecret] = orgId
|
|
59
|
+
? await Promise.all([getOrgDomain(orgId), getOrgA2ASecret(orgId)])
|
|
60
|
+
: [null, null];
|
|
61
|
+
let token;
|
|
62
|
+
try {
|
|
63
|
+
token = await signA2AToken(email, orgDomain?.trim() || undefined, orgSecret?.trim() || undefined, {
|
|
64
|
+
expiresIn: "1m",
|
|
65
|
+
preferGlobalSecret: true,
|
|
66
|
+
...(orgId ? { extraClaims: { org_id: orgId } } : {}),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("[workspace-app-access] registry token unavailable", error);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
const timeout = setTimeout(() => controller.abort(), WORKSPACE_APP_ACCESS_TIMEOUT_MS);
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(url, {
|
|
77
|
+
headers: {
|
|
78
|
+
accept: "application/json",
|
|
79
|
+
Authorization: `Bearer ${token}`,
|
|
80
|
+
},
|
|
81
|
+
signal: controller.signal,
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok)
|
|
84
|
+
return false;
|
|
85
|
+
const apps = workspaceAppsFromResponse(
|
|
86
|
+
// coercion-ok: malformed registry JSON is an authorization failure.
|
|
87
|
+
await response.json().catch(() => null));
|
|
88
|
+
return apps.some((app) => app.id === appId);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error("[workspace-app-access] registry access check failed", error);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
clearTimeout(timeout);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Enforce the workspace-app ACL before a hosted app's authenticated API
|
|
100
|
+
* surface is reached. The app shell remains cacheable and anonymous; this
|
|
101
|
+
* check protects the session-backed APIs/actions that make the app useful.
|
|
102
|
+
*/
|
|
103
|
+
export async function isWorkspaceAppAccessAllowed(appId, context) {
|
|
104
|
+
const normalizedAppId = appId.trim();
|
|
105
|
+
const email = normalizedEmail(context.email);
|
|
106
|
+
if (!normalizedAppId || normalizedAppId === "dispatch" || !email) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
const hostedAccess = await hostedWorkspaceAppAccess(normalizedAppId, context, email);
|
|
110
|
+
if (hostedAccess !== null)
|
|
111
|
+
return hostedAccess;
|
|
112
|
+
// Standalone/local deployments have no Dispatch registry URL. Keep the
|
|
113
|
+
// direct lookup for that mode, but never let missing or malformed ACL state
|
|
114
|
+
// grant access.
|
|
115
|
+
try {
|
|
116
|
+
const db = getDbExec();
|
|
117
|
+
const appResult = await db.execute({
|
|
118
|
+
sql: `SELECT owner_email, org_id, visibility
|
|
119
|
+
FROM workspace_apps WHERE id = ? LIMIT 1`,
|
|
120
|
+
args: [normalizedAppId],
|
|
121
|
+
});
|
|
122
|
+
const app = appResult.rows[0];
|
|
123
|
+
if (!app)
|
|
124
|
+
return false;
|
|
125
|
+
const ownerEmail = normalizedEmail(typeof app.owner_email === "string" ? app.owner_email : "");
|
|
126
|
+
const resourceOrgId = (typeof app.org_id === "string" ? app.org_id : "").trim() || null;
|
|
127
|
+
const orgId = context.orgId?.trim() || null;
|
|
128
|
+
const sameOrg = !!resourceOrgId && resourceOrgId === orgId;
|
|
129
|
+
if (ownerEmail === email && (!resourceOrgId || sameOrg))
|
|
130
|
+
return true;
|
|
131
|
+
if (!sameOrg || !orgId)
|
|
132
|
+
return false;
|
|
133
|
+
const memberResult = await db.execute({
|
|
134
|
+
sql: `SELECT role FROM org_members
|
|
135
|
+
WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
|
|
136
|
+
args: [orgId, email],
|
|
137
|
+
});
|
|
138
|
+
if (memberResult.rows.length === 0)
|
|
139
|
+
return false;
|
|
140
|
+
const memberRole = String(memberResult.rows[0]?.role ?? "");
|
|
141
|
+
if (memberRole === "owner" || memberRole === "admin")
|
|
142
|
+
return true;
|
|
143
|
+
if (app.visibility === "org")
|
|
144
|
+
return true;
|
|
145
|
+
if (app.visibility !== "private")
|
|
146
|
+
return false;
|
|
147
|
+
const userShare = await db.execute({
|
|
148
|
+
sql: `SELECT 1 FROM workspace_app_shares
|
|
149
|
+
WHERE resource_id = ? AND principal_type = 'user'
|
|
150
|
+
AND LOWER(principal_id) = ? LIMIT 1`,
|
|
151
|
+
args: [normalizedAppId, email],
|
|
152
|
+
});
|
|
153
|
+
if (userShare.rows.length > 0)
|
|
154
|
+
return true;
|
|
155
|
+
const orgShare = await db.execute({
|
|
156
|
+
sql: `SELECT 1 FROM workspace_app_shares
|
|
157
|
+
WHERE resource_id = ? AND principal_type = 'org'
|
|
158
|
+
AND principal_id = ? LIMIT 1`,
|
|
159
|
+
args: [normalizedAppId, orgId],
|
|
160
|
+
});
|
|
161
|
+
if (orgShare.rows.length > 0)
|
|
162
|
+
return true;
|
|
163
|
+
const groupShares = await db.execute({
|
|
164
|
+
sql: `SELECT principal_id FROM workspace_app_shares
|
|
165
|
+
WHERE resource_id = ? AND principal_type = 'group'`,
|
|
166
|
+
args: [normalizedAppId],
|
|
167
|
+
});
|
|
168
|
+
const groupIds = groupShares.rows
|
|
169
|
+
.map((row) => typeof row.principal_id === "string" ? row.principal_id : "")
|
|
170
|
+
.filter(Boolean);
|
|
171
|
+
return workspaceUserGroupsIncludeUser(resourceOrgId, groupIds, email);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
// Missing migrations, missing rows, and every other DB failure deny
|
|
175
|
+
// protected app access until the authoritative ACL is available.
|
|
176
|
+
console.error("[workspace-app-access] access check failed", error);
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -75,10 +75,10 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
+
message?: undefined;
|
|
78
79
|
id?: undefined;
|
|
79
80
|
provider?: undefined;
|
|
80
81
|
deleted?: undefined;
|
|
81
|
-
message?: undefined;
|
|
82
82
|
providers: {
|
|
83
83
|
id: string;
|
|
84
84
|
label: string;
|
|
@@ -93,40 +93,40 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
93
93
|
registered?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
+
message?: undefined;
|
|
97
|
+
count?: undefined;
|
|
96
98
|
id?: undefined;
|
|
97
99
|
deleted?: undefined;
|
|
98
|
-
message?: undefined;
|
|
99
100
|
providers?: undefined;
|
|
100
|
-
count?: undefined;
|
|
101
101
|
found: boolean;
|
|
102
102
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
103
103
|
registered?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
+
message?: undefined;
|
|
107
|
+
count?: undefined;
|
|
106
108
|
provider?: undefined;
|
|
107
109
|
deleted?: undefined;
|
|
108
|
-
message?: undefined;
|
|
109
110
|
providers?: undefined;
|
|
110
|
-
count?: undefined;
|
|
111
111
|
found: boolean;
|
|
112
112
|
id: string;
|
|
113
113
|
registered?: undefined;
|
|
114
114
|
label?: undefined;
|
|
115
115
|
} | {
|
|
116
|
-
provider?: undefined;
|
|
117
116
|
message?: undefined;
|
|
118
|
-
providers?: undefined;
|
|
119
117
|
count?: undefined;
|
|
118
|
+
provider?: undefined;
|
|
119
|
+
providers?: undefined;
|
|
120
120
|
found?: undefined;
|
|
121
121
|
deleted: boolean;
|
|
122
122
|
id: string;
|
|
123
123
|
registered?: undefined;
|
|
124
124
|
label?: undefined;
|
|
125
125
|
} | {
|
|
126
|
+
count?: undefined;
|
|
126
127
|
provider?: undefined;
|
|
127
128
|
deleted?: undefined;
|
|
128
129
|
providers?: undefined;
|
|
129
|
-
count?: undefined;
|
|
130
130
|
found?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
@@ -312,6 +312,7 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
314
|
id?: undefined;
|
|
315
|
+
deleted?: undefined;
|
|
315
316
|
providers: {
|
|
316
317
|
id: string;
|
|
317
318
|
label: string;
|
|
@@ -324,27 +325,26 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
324
325
|
count: number;
|
|
325
326
|
provider?: undefined;
|
|
326
327
|
found?: undefined;
|
|
327
|
-
deleted?: undefined;
|
|
328
328
|
registered?: undefined;
|
|
329
329
|
label?: undefined;
|
|
330
330
|
message?: undefined;
|
|
331
331
|
} | {
|
|
332
332
|
id?: undefined;
|
|
333
|
+
deleted?: undefined;
|
|
333
334
|
providers?: undefined;
|
|
334
335
|
count?: undefined;
|
|
335
336
|
found: boolean;
|
|
336
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
337
|
-
deleted?: undefined;
|
|
338
338
|
registered?: undefined;
|
|
339
339
|
label?: undefined;
|
|
340
340
|
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
+
deleted?: undefined;
|
|
342
343
|
providers?: undefined;
|
|
343
344
|
count?: undefined;
|
|
344
345
|
provider?: undefined;
|
|
345
346
|
found: boolean;
|
|
346
347
|
id: string;
|
|
347
|
-
deleted?: undefined;
|
|
348
348
|
registered?: undefined;
|
|
349
349
|
label?: undefined;
|
|
350
350
|
message?: undefined;
|
|
@@ -359,11 +359,11 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
359
359
|
label?: undefined;
|
|
360
360
|
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
+
deleted?: undefined;
|
|
362
363
|
providers?: undefined;
|
|
363
364
|
count?: undefined;
|
|
364
365
|
provider?: undefined;
|
|
365
366
|
found?: undefined;
|
|
366
|
-
deleted?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|