@objectstack/client 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -111,6 +111,41 @@ var FilterBuilder = class {
111
111
  this.conditions.push([field, "is_not_null", null]);
112
112
  return this;
113
113
  }
114
+ /**
115
+ * BETWEEN filter: field BETWEEN min AND max
116
+ */
117
+ between(field, min, max) {
118
+ this.conditions.push(["and", [field, ">=", min], [field, "<=", max]]);
119
+ return this;
120
+ }
121
+ /**
122
+ * CONTAINS filter: field contains value (case-insensitive LIKE %value%)
123
+ */
124
+ contains(field, value) {
125
+ this.conditions.push([field, "like", `%${value}%`]);
126
+ return this;
127
+ }
128
+ /**
129
+ * STARTS WITH filter: field starts with value (LIKE value%)
130
+ */
131
+ startsWith(field, value) {
132
+ this.conditions.push([field, "like", `${value}%`]);
133
+ return this;
134
+ }
135
+ /**
136
+ * ENDS WITH filter: field ends with value (LIKE %value)
137
+ */
138
+ endsWith(field, value) {
139
+ this.conditions.push([field, "like", `%${value}`]);
140
+ return this;
141
+ }
142
+ /**
143
+ * EXISTS filter: field is not null (alias for isNotNull)
144
+ */
145
+ exists(field) {
146
+ this.conditions.push([field, "is_not_null", null]);
147
+ return this;
148
+ }
114
149
  /**
115
150
  * Build the filter condition
116
151
  */
@@ -206,6 +241,37 @@ var QueryBuilder = class {
206
241
  this.query.groupBy = fields;
207
242
  return this;
208
243
  }
244
+ /**
245
+ * Expand (eager-load) a related object with an optional sub-query
246
+ */
247
+ expand(relation, subQuery) {
248
+ if (!this.query.expand) {
249
+ this.query.expand = {};
250
+ }
251
+ this.query.expand[relation] = subQuery || {};
252
+ return this;
253
+ }
254
+ /**
255
+ * Add full-text search
256
+ */
257
+ search(query, options) {
258
+ this.query.search = { query, ...options };
259
+ return this;
260
+ }
261
+ /**
262
+ * Set cursor for keyset pagination
263
+ */
264
+ cursor(cursor) {
265
+ this.query.cursor = cursor;
266
+ return this;
267
+ }
268
+ /**
269
+ * Enable SELECT DISTINCT
270
+ */
271
+ distinct() {
272
+ this.query.distinct = true;
273
+ return this;
274
+ }
209
275
  /**
210
276
  * Build the final query AST
211
277
  */
@@ -363,36 +429,6 @@ var ObjectStackClient = class {
363
429
  return res.json();
364
430
  }
365
431
  };
366
- /**
367
- * Hub Management Services
368
- */
369
- this.hub = {
370
- spaces: {
371
- list: async () => {
372
- const route = this.getRoute("hub");
373
- const res = await this.fetch(`${this.baseUrl}${route}/spaces`);
374
- return res.json();
375
- },
376
- create: async (payload) => {
377
- const route = this.getRoute("hub");
378
- const res = await this.fetch(`${this.baseUrl}${route}/spaces`, {
379
- method: "POST",
380
- body: JSON.stringify(payload)
381
- });
382
- return res.json();
383
- }
384
- },
385
- plugins: {
386
- install: async (pkg, version) => {
387
- const route = this.getRoute("hub");
388
- const res = await this.fetch(`${this.baseUrl}${route}/plugins/install`, {
389
- method: "POST",
390
- body: JSON.stringify({ pkg, version })
391
- });
392
- return res.json();
393
- }
394
- }
395
- };
396
432
  /**
397
433
  * Package Management Services
398
434
  *
@@ -503,6 +539,36 @@ var ObjectStackClient = class {
503
539
  const route = this.getRoute("auth");
504
540
  const res = await this.fetch(`${this.baseUrl}${route}/me`);
505
541
  return res.json();
542
+ },
543
+ /**
544
+ * Register a new user account
545
+ */
546
+ register: async (request) => {
547
+ const route = this.getRoute("auth");
548
+ const res = await this.fetch(`${this.baseUrl}${route}/register`, {
549
+ method: "POST",
550
+ body: JSON.stringify(request)
551
+ });
552
+ const data = await res.json();
553
+ if (data.data?.token) {
554
+ this.token = data.data.token;
555
+ }
556
+ return data;
557
+ },
558
+ /**
559
+ * Refresh an authentication token
560
+ */
561
+ refreshToken: async (refreshToken) => {
562
+ const route = this.getRoute("auth");
563
+ const res = await this.fetch(`${this.baseUrl}${route}/refresh`, {
564
+ method: "POST",
565
+ body: JSON.stringify({ refreshToken })
566
+ });
567
+ const data = await res.json();
568
+ if (data.data?.token) {
569
+ this.token = data.data.token;
570
+ }
571
+ return data;
506
572
  }
507
573
  };
508
574
  /**
@@ -559,6 +625,384 @@ var ObjectStackClient = class {
559
625
  return res.json();
560
626
  }
561
627
  };
628
+ /**
629
+ * Permissions Services
630
+ */
631
+ this.permissions = {
632
+ /**
633
+ * Check if current user has permission for an action on an object
634
+ */
635
+ check: async (request) => {
636
+ const route = this.getRoute("permissions");
637
+ const res = await this.fetch(`${this.baseUrl}${route}/check`, {
638
+ method: "POST",
639
+ body: JSON.stringify(request)
640
+ });
641
+ return this.unwrapResponse(res);
642
+ },
643
+ /**
644
+ * Get all permissions for a specific object
645
+ */
646
+ getObjectPermissions: async (object) => {
647
+ const route = this.getRoute("permissions");
648
+ const res = await this.fetch(`${this.baseUrl}${route}/permissions/${encodeURIComponent(object)}`);
649
+ return this.unwrapResponse(res);
650
+ },
651
+ /**
652
+ * Get effective permissions for the current user
653
+ */
654
+ getEffectivePermissions: async () => {
655
+ const route = this.getRoute("permissions");
656
+ const res = await this.fetch(`${this.baseUrl}${route}/permissions/effective`);
657
+ return this.unwrapResponse(res);
658
+ }
659
+ };
660
+ /**
661
+ * Realtime Services
662
+ */
663
+ this.realtime = {
664
+ /**
665
+ * Establish a realtime connection
666
+ */
667
+ connect: async (request) => {
668
+ const route = this.getRoute("realtime");
669
+ const res = await this.fetch(`${this.baseUrl}${route}/connect`, {
670
+ method: "POST",
671
+ body: JSON.stringify(request || {})
672
+ });
673
+ return this.unwrapResponse(res);
674
+ },
675
+ /**
676
+ * Disconnect from realtime services
677
+ */
678
+ disconnect: async () => {
679
+ const route = this.getRoute("realtime");
680
+ await this.fetch(`${this.baseUrl}${route}/disconnect`, {
681
+ method: "POST"
682
+ });
683
+ },
684
+ /**
685
+ * Subscribe to a channel
686
+ */
687
+ subscribe: async (request) => {
688
+ const route = this.getRoute("realtime");
689
+ const res = await this.fetch(`${this.baseUrl}${route}/subscribe`, {
690
+ method: "POST",
691
+ body: JSON.stringify(request)
692
+ });
693
+ return this.unwrapResponse(res);
694
+ },
695
+ /**
696
+ * Unsubscribe from a channel
697
+ */
698
+ unsubscribe: async (subscriptionId) => {
699
+ const route = this.getRoute("realtime");
700
+ await this.fetch(`${this.baseUrl}${route}/unsubscribe`, {
701
+ method: "POST",
702
+ body: JSON.stringify({ subscriptionId })
703
+ });
704
+ },
705
+ /**
706
+ * Set presence state on a channel
707
+ */
708
+ setPresence: async (channel, state) => {
709
+ const route = this.getRoute("realtime");
710
+ await this.fetch(`${this.baseUrl}${route}/presence`, {
711
+ method: "PUT",
712
+ body: JSON.stringify({ channel, state })
713
+ });
714
+ },
715
+ /**
716
+ * Get presence information for a channel
717
+ */
718
+ getPresence: async (channel) => {
719
+ const route = this.getRoute("realtime");
720
+ const res = await this.fetch(`${this.baseUrl}${route}/presence/${encodeURIComponent(channel)}`);
721
+ return this.unwrapResponse(res);
722
+ }
723
+ };
724
+ /**
725
+ * Workflow Services
726
+ */
727
+ this.workflow = {
728
+ /**
729
+ * Get workflow configuration for an object
730
+ */
731
+ getConfig: async (object) => {
732
+ const route = this.getRoute("workflow");
733
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/config`);
734
+ return this.unwrapResponse(res);
735
+ },
736
+ /**
737
+ * Get current workflow state for a record
738
+ */
739
+ getState: async (object, recordId) => {
740
+ const route = this.getRoute("workflow");
741
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(recordId)}/state`);
742
+ return this.unwrapResponse(res);
743
+ },
744
+ /**
745
+ * Execute a workflow state transition
746
+ */
747
+ transition: async (request) => {
748
+ const route = this.getRoute("workflow");
749
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(request.object)}/${encodeURIComponent(request.recordId)}/transition`, {
750
+ method: "POST",
751
+ body: JSON.stringify({
752
+ transition: request.transition,
753
+ comment: request.comment,
754
+ data: request.data
755
+ })
756
+ });
757
+ return this.unwrapResponse(res);
758
+ },
759
+ /**
760
+ * Approve a workflow step
761
+ */
762
+ approve: async (request) => {
763
+ const route = this.getRoute("workflow");
764
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(request.object)}/${encodeURIComponent(request.recordId)}/approve`, {
765
+ method: "POST",
766
+ body: JSON.stringify({
767
+ comment: request.comment,
768
+ data: request.data
769
+ })
770
+ });
771
+ return this.unwrapResponse(res);
772
+ },
773
+ /**
774
+ * Reject a workflow step
775
+ */
776
+ reject: async (request) => {
777
+ const route = this.getRoute("workflow");
778
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(request.object)}/${encodeURIComponent(request.recordId)}/reject`, {
779
+ method: "POST",
780
+ body: JSON.stringify({
781
+ reason: request.reason,
782
+ comment: request.comment
783
+ })
784
+ });
785
+ return this.unwrapResponse(res);
786
+ }
787
+ };
788
+ /**
789
+ * Views CRUD Services
790
+ */
791
+ this.views = {
792
+ /**
793
+ * List views for an object
794
+ */
795
+ list: async (object, type) => {
796
+ const route = this.getRoute("views");
797
+ const params = new URLSearchParams();
798
+ if (type) params.set("type", type);
799
+ const qs = params.toString();
800
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}${qs ? `?${qs}` : ""}`);
801
+ return this.unwrapResponse(res);
802
+ },
803
+ /**
804
+ * Get a specific view
805
+ */
806
+ get: async (object, viewId) => {
807
+ const route = this.getRoute("views");
808
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(viewId)}`);
809
+ return this.unwrapResponse(res);
810
+ },
811
+ /**
812
+ * Create a new view
813
+ */
814
+ create: async (object, data) => {
815
+ const route = this.getRoute("views");
816
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}`, {
817
+ method: "POST",
818
+ body: JSON.stringify({ object, data })
819
+ });
820
+ return this.unwrapResponse(res);
821
+ },
822
+ /**
823
+ * Update an existing view
824
+ */
825
+ update: async (object, viewId, data) => {
826
+ const route = this.getRoute("views");
827
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(viewId)}`, {
828
+ method: "PUT",
829
+ body: JSON.stringify({ object, viewId, data })
830
+ });
831
+ return this.unwrapResponse(res);
832
+ },
833
+ /**
834
+ * Delete a view
835
+ */
836
+ delete: async (object, viewId) => {
837
+ const route = this.getRoute("views");
838
+ const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(object)}/${encodeURIComponent(viewId)}`, {
839
+ method: "DELETE"
840
+ });
841
+ return this.unwrapResponse(res);
842
+ }
843
+ };
844
+ /**
845
+ * Notification Services
846
+ */
847
+ this.notifications = {
848
+ /**
849
+ * Register a device for push notifications
850
+ */
851
+ registerDevice: async (request) => {
852
+ const route = this.getRoute("notifications");
853
+ const res = await this.fetch(`${this.baseUrl}${route}/devices`, {
854
+ method: "POST",
855
+ body: JSON.stringify(request)
856
+ });
857
+ return this.unwrapResponse(res);
858
+ },
859
+ /**
860
+ * Unregister a device from push notifications
861
+ */
862
+ unregisterDevice: async (deviceId) => {
863
+ const route = this.getRoute("notifications");
864
+ const res = await this.fetch(`${this.baseUrl}${route}/devices/${encodeURIComponent(deviceId)}`, {
865
+ method: "DELETE"
866
+ });
867
+ return this.unwrapResponse(res);
868
+ },
869
+ /**
870
+ * Get notification preferences for the current user
871
+ */
872
+ getPreferences: async () => {
873
+ const route = this.getRoute("notifications");
874
+ const res = await this.fetch(`${this.baseUrl}${route}/preferences`);
875
+ return this.unwrapResponse(res);
876
+ },
877
+ /**
878
+ * Update notification preferences
879
+ */
880
+ updatePreferences: async (preferences) => {
881
+ const route = this.getRoute("notifications");
882
+ const res = await this.fetch(`${this.baseUrl}${route}/preferences`, {
883
+ method: "PUT",
884
+ body: JSON.stringify({ preferences })
885
+ });
886
+ return this.unwrapResponse(res);
887
+ },
888
+ /**
889
+ * List notifications for the current user
890
+ */
891
+ list: async (options) => {
892
+ const route = this.getRoute("notifications");
893
+ const params = new URLSearchParams();
894
+ if (options?.read !== void 0) params.set("read", String(options.read));
895
+ if (options?.type) params.set("type", options.type);
896
+ if (options?.limit) params.set("limit", String(options.limit));
897
+ if (options?.cursor) params.set("cursor", options.cursor);
898
+ const qs = params.toString();
899
+ const res = await this.fetch(`${this.baseUrl}${route}${qs ? `?${qs}` : ""}`);
900
+ return this.unwrapResponse(res);
901
+ },
902
+ /**
903
+ * Mark specific notifications as read
904
+ */
905
+ markRead: async (ids) => {
906
+ const route = this.getRoute("notifications");
907
+ const res = await this.fetch(`${this.baseUrl}${route}/read`, {
908
+ method: "POST",
909
+ body: JSON.stringify({ ids })
910
+ });
911
+ return this.unwrapResponse(res);
912
+ },
913
+ /**
914
+ * Mark all notifications as read
915
+ */
916
+ markAllRead: async () => {
917
+ const route = this.getRoute("notifications");
918
+ const res = await this.fetch(`${this.baseUrl}${route}/read/all`, {
919
+ method: "POST"
920
+ });
921
+ return this.unwrapResponse(res);
922
+ }
923
+ };
924
+ /**
925
+ * AI Services
926
+ */
927
+ this.ai = {
928
+ /**
929
+ * Natural language query — converts natural language to structured query
930
+ */
931
+ nlq: async (request) => {
932
+ const route = this.getRoute("ai");
933
+ const res = await this.fetch(`${this.baseUrl}${route}/nlq`, {
934
+ method: "POST",
935
+ body: JSON.stringify(request)
936
+ });
937
+ return this.unwrapResponse(res);
938
+ },
939
+ /**
940
+ * Multi-turn AI chat
941
+ */
942
+ chat: async (request) => {
943
+ const route = this.getRoute("ai");
944
+ const res = await this.fetch(`${this.baseUrl}${route}/chat`, {
945
+ method: "POST",
946
+ body: JSON.stringify(request)
947
+ });
948
+ return this.unwrapResponse(res);
949
+ },
950
+ /**
951
+ * AI-powered field value suggestions
952
+ */
953
+ suggest: async (request) => {
954
+ const route = this.getRoute("ai");
955
+ const res = await this.fetch(`${this.baseUrl}${route}/suggest`, {
956
+ method: "POST",
957
+ body: JSON.stringify(request)
958
+ });
959
+ return this.unwrapResponse(res);
960
+ },
961
+ /**
962
+ * AI-powered data insights
963
+ */
964
+ insights: async (request) => {
965
+ const route = this.getRoute("ai");
966
+ const res = await this.fetch(`${this.baseUrl}${route}/insights`, {
967
+ method: "POST",
968
+ body: JSON.stringify(request)
969
+ });
970
+ return this.unwrapResponse(res);
971
+ }
972
+ };
973
+ /**
974
+ * Internationalization Services
975
+ */
976
+ this.i18n = {
977
+ /**
978
+ * Get available locales
979
+ */
980
+ getLocales: async () => {
981
+ const route = this.getRoute("i18n");
982
+ const res = await this.fetch(`${this.baseUrl}${route}/locales`);
983
+ return this.unwrapResponse(res);
984
+ },
985
+ /**
986
+ * Get translations for a locale
987
+ */
988
+ getTranslations: async (locale, options) => {
989
+ const route = this.getRoute("i18n");
990
+ const params = new URLSearchParams();
991
+ params.set("locale", locale);
992
+ if (options?.namespace) params.set("namespace", options.namespace);
993
+ if (options?.keys) params.set("keys", options.keys.join(","));
994
+ const res = await this.fetch(`${this.baseUrl}${route}/translations?${params.toString()}`);
995
+ return this.unwrapResponse(res);
996
+ },
997
+ /**
998
+ * Get translated field labels for an object
999
+ */
1000
+ getFieldLabels: async (object, locale) => {
1001
+ const route = this.getRoute("i18n");
1002
+ const res = await this.fetch(`${this.baseUrl}${route}/labels/${encodeURIComponent(object)}?locale=${encodeURIComponent(locale)}`);
1003
+ return this.unwrapResponse(res);
1004
+ }
1005
+ };
562
1006
  /**
563
1007
  * Data Operations
564
1008
  */
@@ -829,10 +1273,17 @@ var ObjectStackClient = class {
829
1273
  ui: "/api/v1/ui",
830
1274
  auth: "/api/v1/auth",
831
1275
  analytics: "/api/v1/analytics",
832
- hub: "/api/v1/hub",
833
1276
  storage: "/api/v1/storage",
834
1277
  automation: "/api/v1/automation",
835
- packages: "/api/v1/packages"
1278
+ packages: "/api/v1/packages",
1279
+ permissions: "/api/v1/auth",
1280
+ // Permission endpoints are under /api/v1/auth per spec
1281
+ realtime: "/api/v1/realtime",
1282
+ workflow: "/api/v1/workflow",
1283
+ views: "/api/v1/ui/views",
1284
+ notifications: "/api/v1/notifications",
1285
+ ai: "/api/v1/ai",
1286
+ i18n: "/api/v1/i18n"
836
1287
  };
837
1288
  return routeMap[type] || `/api/v1/${type}`;
838
1289
  }