@colixsystems/datastore-client 0.4.0 → 0.6.0
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/README.md +94 -34
- package/dist/client.js +364 -93
- package/dist/client.test.js +298 -63
- package/dist/index.d.ts +133 -78
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,27 +1,60 @@
|
|
|
1
1
|
// Hand-written ambient types for @colixsystems/datastore-client.
|
|
2
2
|
// The package is plain ESM JavaScript; this file is shipped for IDE
|
|
3
3
|
// IntelliSense. Keep in sync with src/index.js when adding exports.
|
|
4
|
+
//
|
|
5
|
+
// CONTRACT: snake_case in BOTH directions. Wire fields are snake_case
|
|
6
|
+
// verbatim (`table_id`, `created_at`, `can_read`, …) and the client does NO
|
|
7
|
+
// case transform. The only camelCase here is JS method names and the factory
|
|
8
|
+
// option names. This is the DATA PLANE only — tables, records, aggregates,
|
|
9
|
+
// and record-level permissions. Users / groups / files / payments live in
|
|
10
|
+
// sibling packages.
|
|
11
|
+
|
|
12
|
+
// A column on a virtual table (snake_case wire shape).
|
|
13
|
+
export interface Column {
|
|
14
|
+
id: string;
|
|
15
|
+
table_id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
data_type: string;
|
|
18
|
+
required?: boolean;
|
|
19
|
+
target_table_id?: string | null;
|
|
20
|
+
relation_type?: string | null;
|
|
21
|
+
is_identification_column?: boolean;
|
|
22
|
+
encrypted?: boolean;
|
|
23
|
+
inherit_acl?: boolean;
|
|
24
|
+
default_value?: unknown;
|
|
25
|
+
created_at?: string;
|
|
26
|
+
updated_at?: string;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
4
29
|
|
|
5
|
-
|
|
30
|
+
// The full table schema returned by `tables.get(idOrName)` / `schema(t)`.
|
|
31
|
+
export interface Table {
|
|
6
32
|
id: string;
|
|
33
|
+
tenant_id?: string;
|
|
7
34
|
name: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
35
|
+
grant_creator_permissions?: boolean;
|
|
36
|
+
allow_anonymous_create?: boolean;
|
|
37
|
+
html_template?: string | null;
|
|
38
|
+
columns?: Column[];
|
|
39
|
+
created_at?: string;
|
|
40
|
+
updated_at?: string;
|
|
41
|
+
deleted_at?: string | null;
|
|
42
|
+
[key: string]: unknown;
|
|
14
43
|
}
|
|
15
44
|
|
|
45
|
+
// A free-form record. Keys correspond to the table's column `name`s; the
|
|
46
|
+
// host-managed fields are snake_case (`id`, `created_at`, `updated_at`).
|
|
16
47
|
export interface Record_ {
|
|
17
48
|
id: string;
|
|
49
|
+
created_at?: string;
|
|
50
|
+
updated_at?: string;
|
|
18
51
|
[key: string]: unknown;
|
|
19
52
|
}
|
|
20
53
|
export { Record_ as Record };
|
|
21
54
|
|
|
22
55
|
// The uniform list envelope every collection endpoint returns
|
|
23
|
-
// (`{ data, meta }`). `meta.total` is the ACL-aware row
|
|
24
|
-
// with `limit
|
|
56
|
+
// (`{ data, meta }`), returned VERBATIM. `meta.total` is the ACL-aware row
|
|
57
|
+
// count; use it with `limit` / `offset` to page.
|
|
25
58
|
export interface Page<T> {
|
|
26
59
|
data: T[];
|
|
27
60
|
meta: {
|
|
@@ -34,93 +67,78 @@ export interface Page<T> {
|
|
|
34
67
|
// Record-list query. A `filter` maps a column name to an `op:value`
|
|
35
68
|
// expression — e.g. `{ status: "eq:Open", priority: "gte:3" }`. Supported
|
|
36
69
|
// operators: eq, neq, lt, gt, gte, lte, contains, empty, nempty (and the
|
|
37
|
-
// `me` sentinel for USER columns). `filterMode` ANDs conditions
|
|
38
|
-
// default, or ORs them. `q` is a free-text search
|
|
39
|
-
// string/text columns.
|
|
70
|
+
// `me` sentinel for USER / USER_GROUP columns). `filterMode` ANDs conditions
|
|
71
|
+
// by default, or ORs them (sent as `filter_mode`). `q` is a free-text search
|
|
72
|
+
// across the table's string/text columns. `sort` is a column name optionally
|
|
73
|
+
// prefixed with `-` for descending (e.g. `-created_at`). Pagination is
|
|
74
|
+
// `limit` + `offset`.
|
|
40
75
|
export interface Query {
|
|
41
|
-
filter?:
|
|
76
|
+
filter?: { [column: string]: string };
|
|
42
77
|
filterMode?: "and" | "or";
|
|
43
78
|
q?: string;
|
|
79
|
+
sort?: string;
|
|
44
80
|
limit?: number;
|
|
45
81
|
offset?: number;
|
|
46
82
|
}
|
|
47
83
|
|
|
48
84
|
// Aggregate request: group rows by a single column and (optionally) sum a
|
|
49
|
-
// single numeric field, with the same `filter` map the list accepts.
|
|
85
|
+
// single numeric field, with the same `filter` map the list accepts. Sent as
|
|
86
|
+
// `group_by` / `sum_field` on the wire.
|
|
50
87
|
export interface AggregateSpec {
|
|
51
88
|
groupBy?: string;
|
|
52
89
|
sumField?: string;
|
|
53
|
-
filter?:
|
|
90
|
+
filter?: { [column: string]: string };
|
|
54
91
|
}
|
|
55
92
|
|
|
56
93
|
// Aggregate response: one row per group with the row count and the sum of
|
|
57
|
-
// `
|
|
94
|
+
// `sum_field` (0 when no `sum_field` was requested).
|
|
58
95
|
export type AggregateResult = Array<{
|
|
59
96
|
group: string;
|
|
60
97
|
count: number;
|
|
61
98
|
sum: number;
|
|
62
99
|
}>;
|
|
63
100
|
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
email?: string | null;
|
|
71
|
-
role?: string;
|
|
72
|
-
groupIds?: string[];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface Group {
|
|
101
|
+
// A single row-level grant on a record (REQ-ACL-06), snake_case verbatim.
|
|
102
|
+
// Exactly one of `user_id` / `group_id` is set; the four `can_*` flags are
|
|
103
|
+
// the capability bits. `source_kind` / `source_id` are non-null only for
|
|
104
|
+
// grants cascaded from a parent record through an inheriting relation —
|
|
105
|
+
// directly-authored grants have both null.
|
|
106
|
+
export interface RecordPermission {
|
|
76
107
|
id: string;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
108
|
+
table_id: string;
|
|
109
|
+
record_id: string | null;
|
|
110
|
+
user_id: string | null;
|
|
111
|
+
group_id: string | null;
|
|
112
|
+
can_read: boolean;
|
|
113
|
+
can_write: boolean;
|
|
114
|
+
can_delete: boolean;
|
|
115
|
+
can_grant: boolean;
|
|
116
|
+
source_kind: string | null;
|
|
117
|
+
source_id: string | null;
|
|
118
|
+
created_at: string;
|
|
119
|
+
updated_at: string;
|
|
81
120
|
}
|
|
82
121
|
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
// from a parent record through an inheriting relation — directly-authored
|
|
87
|
-
// grants have both null.
|
|
88
|
-
export interface RecordPermission {
|
|
89
|
-
id: string;
|
|
90
|
-
tableId: string;
|
|
91
|
-
recordId: string | null;
|
|
92
|
-
userId: string | null;
|
|
93
|
-
groupId: string | null;
|
|
94
|
-
canRead: boolean;
|
|
95
|
-
canWrite: boolean;
|
|
96
|
-
canDelete: boolean;
|
|
97
|
-
canGrant: boolean;
|
|
98
|
-
sourceKind: string | null;
|
|
99
|
-
sourceId: string | null;
|
|
100
|
-
createdAt: string;
|
|
101
|
-
updatedAt: string;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Grant body for `permissions(recordId).grant(...)`. Provide exactly ONE of
|
|
105
|
-
// `userId` or `groupId`. Flags default server-side to `canRead: true` and
|
|
106
|
-
// the rest `false` when omitted.
|
|
122
|
+
// Grant body for `permissions(recordId).grant(...)`, sent snake_case
|
|
123
|
+
// verbatim. Provide exactly ONE of `user_id` or `group_id`. Flags default
|
|
124
|
+
// server-side to `can_read: true` and the rest `false` when omitted.
|
|
107
125
|
export interface RecordPermissionGrant {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
user_id?: string | null;
|
|
127
|
+
group_id?: string | null;
|
|
128
|
+
can_read?: boolean;
|
|
129
|
+
can_write?: boolean;
|
|
130
|
+
can_delete?: boolean;
|
|
131
|
+
can_grant?: boolean;
|
|
114
132
|
}
|
|
115
133
|
|
|
116
|
-
// Flag patch for `permissions(recordId).update(...)
|
|
117
|
-
// capability bits are mutable; the grantee is fixed
|
|
118
|
-
// flags are left unchanged.
|
|
134
|
+
// Flag patch for `permissions(recordId).update(...)`, sent snake_case
|
|
135
|
+
// verbatim. Only the four capability bits are mutable; the grantee is fixed
|
|
136
|
+
// at grant time. Omitted flags are left unchanged.
|
|
119
137
|
export interface RecordPermissionPatch {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
can_read?: boolean;
|
|
139
|
+
can_write?: boolean;
|
|
140
|
+
can_delete?: boolean;
|
|
141
|
+
can_grant?: boolean;
|
|
124
142
|
}
|
|
125
143
|
|
|
126
144
|
export interface RecordPermissionsNamespace {
|
|
@@ -133,6 +151,29 @@ export interface RecordPermissionsNamespace {
|
|
|
133
151
|
revoke(permissionId: string): Promise<void>;
|
|
134
152
|
}
|
|
135
153
|
|
|
154
|
+
// REQ-RT-07 realtime subscription transport state, reported via
|
|
155
|
+
// `subscribe({ onStatus })`. "live" = socket open + subscribe acked;
|
|
156
|
+
// "fallback" = the caller should poll (no WebSocket impl, subscribe rejected
|
|
157
|
+
// by ACL, or the first connect timed out).
|
|
158
|
+
export type SubscriptionStatus =
|
|
159
|
+
| "connecting"
|
|
160
|
+
| "live"
|
|
161
|
+
| "reconnecting"
|
|
162
|
+
| "fallback";
|
|
163
|
+
|
|
164
|
+
export interface SubscriptionHandlers {
|
|
165
|
+
onCreated?: (record: Record_) => void;
|
|
166
|
+
onUpdated?: (record: Record_) => void;
|
|
167
|
+
onDeleted?: (record: Record_) => void;
|
|
168
|
+
onStatus?: (status: SubscriptionStatus) => void;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface SubscriptionOptions {
|
|
172
|
+
// Emit "fallback" if the first subscribe doesn't land within this many ms
|
|
173
|
+
// (default 3000) so the caller can start polling without waiting forever.
|
|
174
|
+
fallbackAfterMs?: number;
|
|
175
|
+
}
|
|
176
|
+
|
|
136
177
|
export interface RecordsNamespace {
|
|
137
178
|
list(query?: Query): Promise<Page<Record_>>;
|
|
138
179
|
get(id: string): Promise<Record_>;
|
|
@@ -141,28 +182,42 @@ export interface RecordsNamespace {
|
|
|
141
182
|
delete(id: string): Promise<void>;
|
|
142
183
|
aggregate(spec: AggregateSpec): Promise<AggregateResult>;
|
|
143
184
|
permissions(recordId: string): RecordPermissionsNamespace;
|
|
185
|
+
// REQ-RT-07: subscribe to this table's realtime change stream. Returns a
|
|
186
|
+
// synchronous unsubscribe function.
|
|
187
|
+
subscribe(
|
|
188
|
+
handlers: SubscriptionHandlers,
|
|
189
|
+
options?: SubscriptionOptions,
|
|
190
|
+
): () => void;
|
|
144
191
|
}
|
|
145
192
|
|
|
146
193
|
export interface DatastoreClient {
|
|
147
194
|
tables: {
|
|
148
|
-
list(): Promise<
|
|
149
|
-
get(idOrName: string): Promise<
|
|
195
|
+
list(): Promise<Page<Table>>;
|
|
196
|
+
get(idOrName: string): Promise<Table>;
|
|
150
197
|
};
|
|
198
|
+
// Alias of tables.get for the table's column structure (the host calls
|
|
199
|
+
// ctx.datastore.schema(t)).
|
|
200
|
+
schema(tableId: string): Promise<Table>;
|
|
151
201
|
records(table: string): RecordsNamespace;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
listMine(): Promise<Group[]>;
|
|
158
|
-
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface RequestHeadersContext {
|
|
205
|
+
namespace: string;
|
|
206
|
+
operation: string;
|
|
159
207
|
}
|
|
160
208
|
|
|
161
209
|
export interface CreateDatastoreClientOptions {
|
|
162
210
|
baseUrl: string;
|
|
163
211
|
getToken: () => string | Promise<string>;
|
|
164
212
|
getTenantId: () => string | Promise<string>;
|
|
213
|
+
getRequestHeaders?: (
|
|
214
|
+
ctx: RequestHeadersContext,
|
|
215
|
+
) => Record<string, string> | Promise<Record<string, string>>;
|
|
165
216
|
fetchImpl?: typeof fetch;
|
|
217
|
+
// REQ-RT-07: WebSocket constructor for records(t).subscribe(). Defaults to
|
|
218
|
+
// globalThis.WebSocket (browser + React Native). Omit in environments
|
|
219
|
+
// without one — subscribe() then reports "fallback".
|
|
220
|
+
webSocketImpl?: typeof WebSocket;
|
|
166
221
|
}
|
|
167
222
|
|
|
168
223
|
export function createDatastoreClient(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/datastore-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Typed, scoped client for the AppStudio datastore API
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Typed, scoped data-plane client for the AppStudio datastore API (tables, records, aggregates, record-level permissions, realtime subscribe). snake_case wire contract, no transform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|