@fidscript/instant-react-native 0.1.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/dist/EventSourceImpl.d.ts +10 -0
- package/dist/EventSourceImpl.d.ts.map +1 -0
- package/dist/EventSourceImpl.js +9 -0
- package/dist/EventSourceImpl.js.map +1 -0
- package/dist/EventSourceShim.d.ts +31 -0
- package/dist/EventSourceShim.d.ts.map +1 -0
- package/dist/EventSourceShim.js +228 -0
- package/dist/EventSourceShim.js.map +1 -0
- package/dist/NetworkListener.d.ts +5 -0
- package/dist/NetworkListener.d.ts.map +1 -0
- package/dist/NetworkListener.js +19 -0
- package/dist/NetworkListener.js.map +1 -0
- package/dist/Storage.d.ts +3 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/Storage.js +5 -0
- package/dist/Storage.js.map +1 -0
- package/dist/Storage.native.d.ts +22 -0
- package/dist/Storage.native.d.ts.map +1 -0
- package/dist/Storage.native.js +79 -0
- package/dist/Storage.native.js.map +1 -0
- package/dist/Streams.d.ts +15 -0
- package/dist/Streams.d.ts.map +1 -0
- package/dist/Streams.js +9 -0
- package/dist/Streams.js.map +1 -0
- package/dist/Streams.native.d.ts +6 -0
- package/dist/Streams.native.d.ts.map +1 -0
- package/dist/Streams.native.js +9 -0
- package/dist/Streams.native.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/module/EventSourceImpl.d.ts +10 -0
- package/dist/module/EventSourceImpl.d.ts.map +1 -0
- package/dist/module/EventSourceImpl.js +4 -0
- package/dist/module/EventSourceImpl.js.map +1 -0
- package/dist/module/EventSourceShim.d.ts +31 -0
- package/dist/module/EventSourceShim.d.ts.map +1 -0
- package/dist/module/EventSourceShim.js +226 -0
- package/dist/module/EventSourceShim.js.map +1 -0
- package/dist/module/NetworkListener.d.ts +5 -0
- package/dist/module/NetworkListener.d.ts.map +1 -0
- package/dist/module/NetworkListener.js +13 -0
- package/dist/module/NetworkListener.js.map +1 -0
- package/dist/module/Storage.d.ts +3 -0
- package/dist/module/Storage.d.ts.map +1 -0
- package/dist/module/Storage.js +3 -0
- package/dist/module/Storage.js.map +1 -0
- package/dist/module/Storage.native.d.ts +22 -0
- package/dist/module/Storage.native.d.ts.map +1 -0
- package/dist/module/Storage.native.js +75 -0
- package/dist/module/Storage.native.js.map +1 -0
- package/dist/module/Streams.d.ts +15 -0
- package/dist/module/Streams.d.ts.map +1 -0
- package/dist/module/Streams.js +6 -0
- package/dist/module/Streams.js.map +1 -0
- package/dist/module/Streams.native.d.ts +6 -0
- package/dist/module/Streams.native.d.ts.map +1 -0
- package/dist/module/Streams.native.js +6 -0
- package/dist/module/Streams.native.js.map +1 -0
- package/dist/module/cli.d.ts +2 -0
- package/dist/module/cli.d.ts.map +1 -0
- package/dist/module/cli.js +2 -0
- package/dist/module/cli.js.map +1 -0
- package/dist/module/index.d.ts +56 -0
- package/dist/module/index.d.ts.map +1 -0
- package/dist/module/index.js +76 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/version.d.ts +3 -0
- package/dist/module/version.d.ts.map +1 -0
- package/dist/module/version.js +3 -0
- package/dist/module/version.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +49 -0
- package/src/EventSourceImpl.ts +6 -0
- package/src/EventSourceShim.ts +285 -0
- package/src/NetworkListener.js +13 -0
- package/src/Storage.js +3 -0
- package/src/Storage.native.ts +91 -0
- package/src/Streams.native.ts +6 -0
- package/src/Streams.ts +5 -0
- package/src/__types__/typeUtils.ts +39 -0
- package/src/__types__/typesTests.ts +86 -0
- package/src/cli.ts +1 -0
- package/src/index.ts +290 -0
- package/src/version.ts +2 -0
- package/tsconfig.json +16 -0
- package/tsconfig.module.json +13 -0
- package/tsconfig.test.json +5 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { type EventSourceType } from '@fidscript/instant-sdk';
|
|
2
|
+
|
|
3
|
+
// Modified version of https://github.com/binaryminds/react-native-sse/blob/master/src/EventSource.js
|
|
4
|
+
// that conforms to our `EventSourceType` subset of the browser-native `EventSource`.
|
|
5
|
+
|
|
6
|
+
const XMLReadyStateMap = [
|
|
7
|
+
'UNSENT',
|
|
8
|
+
'OPENED',
|
|
9
|
+
'HEADERS_RECEIVED',
|
|
10
|
+
'LOADING',
|
|
11
|
+
'DONE',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
class EventSource implements EventSourceType {
|
|
15
|
+
private ERROR = -1;
|
|
16
|
+
static CONNECTING = 0;
|
|
17
|
+
static OPEN = 1;
|
|
18
|
+
static CLOSED = 2;
|
|
19
|
+
|
|
20
|
+
private CRLF = '\r\n';
|
|
21
|
+
private LF = '\n';
|
|
22
|
+
private CR = '\r';
|
|
23
|
+
|
|
24
|
+
readonly url: string;
|
|
25
|
+
|
|
26
|
+
onopen;
|
|
27
|
+
onerror;
|
|
28
|
+
onmessage;
|
|
29
|
+
|
|
30
|
+
debug: boolean;
|
|
31
|
+
|
|
32
|
+
private status: number;
|
|
33
|
+
|
|
34
|
+
private headers = {
|
|
35
|
+
Accept: 'text/event-stream',
|
|
36
|
+
'Cache-Control': 'no-cache',
|
|
37
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
private _xhr: XMLHttpRequest | null;
|
|
41
|
+
private lineEndingCharacter: string | null;
|
|
42
|
+
private _lastIndexProcessed: number;
|
|
43
|
+
|
|
44
|
+
constructor(url) {
|
|
45
|
+
this.status = EventSource.CONNECTING;
|
|
46
|
+
|
|
47
|
+
this.lineEndingCharacter = null;
|
|
48
|
+
this._xhr = null;
|
|
49
|
+
this._lastIndexProcessed = 0;
|
|
50
|
+
this.debug = false;
|
|
51
|
+
|
|
52
|
+
if (!url || typeof url !== 'string') {
|
|
53
|
+
throw new SyntaxError('[EventSource] Invalid URL argument.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.url = url;
|
|
57
|
+
|
|
58
|
+
this.open();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public get readyState() {
|
|
62
|
+
if (this.status === this.ERROR) {
|
|
63
|
+
return EventSource.CLOSED;
|
|
64
|
+
}
|
|
65
|
+
return this.status;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
open() {
|
|
69
|
+
try {
|
|
70
|
+
this.status = EventSource.CONNECTING;
|
|
71
|
+
|
|
72
|
+
this._lastIndexProcessed = 0;
|
|
73
|
+
|
|
74
|
+
this._xhr = new XMLHttpRequest();
|
|
75
|
+
this._xhr.open('GET', this.url, true);
|
|
76
|
+
|
|
77
|
+
for (const [key, value] of Object.entries(this.headers)) {
|
|
78
|
+
if (value !== undefined && value !== null) {
|
|
79
|
+
this._xhr.setRequestHeader(key, value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this._xhr.onreadystatechange = () => {
|
|
84
|
+
if (this.status === EventSource.CLOSED) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const xhr = this._xhr!;
|
|
89
|
+
|
|
90
|
+
this._logDebug(
|
|
91
|
+
`[EventSource][onreadystatechange] ReadyState: ${XMLReadyStateMap[xhr.readyState] || 'Unknown'}(${
|
|
92
|
+
xhr.readyState
|
|
93
|
+
}), status: ${xhr.status}`,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
xhr.readyState !== XMLHttpRequest.DONE &&
|
|
98
|
+
xhr.readyState !== XMLHttpRequest.LOADING
|
|
99
|
+
) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (xhr.status >= 200 && xhr.status < 400) {
|
|
104
|
+
if (this.status === EventSource.CONNECTING) {
|
|
105
|
+
this.status = EventSource.OPEN;
|
|
106
|
+
this.dispatch('open', { type: 'open' });
|
|
107
|
+
this._logDebug(
|
|
108
|
+
'[EventSource][onreadystatechange][OPEN] Connection opened.',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this._handleEvent(xhr.responseText || '');
|
|
113
|
+
|
|
114
|
+
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
115
|
+
this._logDebug(
|
|
116
|
+
'[EventSource][onreadystatechange][DONE] Operation done.',
|
|
117
|
+
);
|
|
118
|
+
this.dispatch('error', { type: 'error' });
|
|
119
|
+
}
|
|
120
|
+
} else if (xhr.status !== 0) {
|
|
121
|
+
this.status = this.ERROR;
|
|
122
|
+
this.dispatch('error', {
|
|
123
|
+
type: 'error',
|
|
124
|
+
message: xhr.responseText,
|
|
125
|
+
xhrStatus: xhr.status,
|
|
126
|
+
xhrState: xhr.readyState,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
130
|
+
this._logDebug(
|
|
131
|
+
'[EventSource][onreadystatechange][ERROR] Response status error.',
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
this._xhr.onerror = () => {
|
|
138
|
+
if (this.status === EventSource.CLOSED) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.status = this.ERROR;
|
|
143
|
+
this.dispatch('error', {
|
|
144
|
+
type: 'error',
|
|
145
|
+
message: this._xhr!.responseText,
|
|
146
|
+
xhrStatus: this._xhr!.status,
|
|
147
|
+
xhrState: this._xhr!.readyState,
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
this._xhr.send();
|
|
152
|
+
} catch (e) {
|
|
153
|
+
this.status = this.ERROR;
|
|
154
|
+
this.dispatch('error', {
|
|
155
|
+
type: 'exception',
|
|
156
|
+
message: e.message,
|
|
157
|
+
error: e,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_logDebug(...msg) {
|
|
163
|
+
if (this.debug) {
|
|
164
|
+
console.debug(...msg);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_handleEvent(response) {
|
|
169
|
+
if (this.lineEndingCharacter === null) {
|
|
170
|
+
const detectedNewlineChar = this._detectNewlineChar(response);
|
|
171
|
+
if (detectedNewlineChar !== null) {
|
|
172
|
+
this._logDebug(
|
|
173
|
+
`[EventSource] Automatically detected lineEndingCharacter: ${JSON.stringify(
|
|
174
|
+
detectedNewlineChar,
|
|
175
|
+
).slice(1, -1)}`,
|
|
176
|
+
);
|
|
177
|
+
this.lineEndingCharacter = detectedNewlineChar;
|
|
178
|
+
} else {
|
|
179
|
+
console.warn(
|
|
180
|
+
"[EventSource] Unable to identify the line ending character. Ensure your server delivers a standard line ending character: \\r\\n, \\n, \\r, or specify your custom character using the 'lineEndingCharacter' option.",
|
|
181
|
+
);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const indexOfDoubleNewline = this._getLastDoubleNewlineIndex(response);
|
|
187
|
+
if (indexOfDoubleNewline <= this._lastIndexProcessed) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const parts = response
|
|
192
|
+
.substring(this._lastIndexProcessed, indexOfDoubleNewline)
|
|
193
|
+
.split(this.lineEndingCharacter);
|
|
194
|
+
|
|
195
|
+
this._lastIndexProcessed = indexOfDoubleNewline;
|
|
196
|
+
|
|
197
|
+
let type: string | undefined = undefined;
|
|
198
|
+
let data: string[] = [];
|
|
199
|
+
let line = '';
|
|
200
|
+
|
|
201
|
+
for (let i = 0; i < parts.length; i++) {
|
|
202
|
+
line = parts[i].trim();
|
|
203
|
+
if (line.startsWith('event')) {
|
|
204
|
+
type = line.replace(/event:?\s*/, '');
|
|
205
|
+
} else if (line.startsWith('retry')) {
|
|
206
|
+
// Ignore for our use case, we'll reconnect with a new
|
|
207
|
+
// instance on error
|
|
208
|
+
} else if (line.startsWith('data')) {
|
|
209
|
+
data.push(line.replace(/data:?\s*/, ''));
|
|
210
|
+
} else if (line.startsWith('id')) {
|
|
211
|
+
// Ignore this, not used for our use case
|
|
212
|
+
} else if (line === '') {
|
|
213
|
+
if (data.length > 0) {
|
|
214
|
+
const eventType = type || 'message';
|
|
215
|
+
const event = {
|
|
216
|
+
type: eventType,
|
|
217
|
+
data: data.join('\n'),
|
|
218
|
+
url: this.url,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
this.dispatch(eventType, event);
|
|
222
|
+
|
|
223
|
+
data = [];
|
|
224
|
+
type = undefined;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
_detectNewlineChar(response) {
|
|
231
|
+
const supportedLineEndings = [this.CRLF, this.LF, this.CR];
|
|
232
|
+
for (const char of supportedLineEndings) {
|
|
233
|
+
if (response.includes(char)) {
|
|
234
|
+
return char;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_getLastDoubleNewlineIndex(response) {
|
|
241
|
+
const doubleLineEndingCharacter =
|
|
242
|
+
this.lineEndingCharacter! + this.lineEndingCharacter!;
|
|
243
|
+
const lastIndex = response.lastIndexOf(doubleLineEndingCharacter);
|
|
244
|
+
if (lastIndex === -1) {
|
|
245
|
+
return -1;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return lastIndex + doubleLineEndingCharacter.length;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
dispatch(type, data) {
|
|
252
|
+
switch (type) {
|
|
253
|
+
case 'open': {
|
|
254
|
+
if (this.onopen) {
|
|
255
|
+
this.onopen(data);
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
case 'error': {
|
|
260
|
+
if (this.onerror) {
|
|
261
|
+
this.onerror(data);
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case 'message': {
|
|
266
|
+
if (this.onmessage) {
|
|
267
|
+
this.onmessage(data);
|
|
268
|
+
}
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
close() {
|
|
275
|
+
if (this.status !== EventSource.CLOSED) {
|
|
276
|
+
this.status = EventSource.CLOSED;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (this._xhr) {
|
|
280
|
+
this._xhr.abort();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export default EventSource;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
2
|
+
|
|
3
|
+
export default class NetworkListener {
|
|
4
|
+
static async getIsOnline() {
|
|
5
|
+
const network = await NetInfo.fetch();
|
|
6
|
+
return network.isConnected;
|
|
7
|
+
}
|
|
8
|
+
static listen(f) {
|
|
9
|
+
return NetInfo.addEventListener((state) => {
|
|
10
|
+
f(state.isConnected);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/Storage.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { StoreInterface, StoreInterfaceStoreName } from '@fidscript/instant-sdk';
|
|
2
|
+
|
|
3
|
+
const version = 5;
|
|
4
|
+
|
|
5
|
+
// AsyncStorage is an optional peer dependency. The `require` must sit
|
|
6
|
+
// directly inside a `try` block: that's what makes Metro treat it as an
|
|
7
|
+
// optional dependency (`transformer.allowOptionalDependencies`, enabled by
|
|
8
|
+
// default in the Expo and React Native metro configs), so bundling doesn't
|
|
9
|
+
// fail when it isn't installed. When it can't be loaded, `init` surfaces a
|
|
10
|
+
// helpful error unless a custom `Store` is passed.
|
|
11
|
+
let AsyncStorage: any = null;
|
|
12
|
+
let asyncStorageLoadError: unknown = null;
|
|
13
|
+
try {
|
|
14
|
+
AsyncStorage = require('@react-native-async-storage/async-storage').default;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
asyncStorageLoadError = e;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class AsyncStorageStore extends StoreInterface {
|
|
20
|
+
private appId: string;
|
|
21
|
+
private dbName: StoreInterfaceStoreName;
|
|
22
|
+
constructor(appId: string, dbName: StoreInterfaceStoreName) {
|
|
23
|
+
super(appId, dbName);
|
|
24
|
+
this.appId = appId;
|
|
25
|
+
this.dbName = dbName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private makeKey(k: string): string {
|
|
29
|
+
return `instant_${this.appId}_${version}_${this.dbName}_${k}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async getItem(k) {
|
|
33
|
+
const res = await AsyncStorage.getItem(this.makeKey(k));
|
|
34
|
+
if (res === null) return res;
|
|
35
|
+
return JSON.parse(res);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async setItem(k, v) {
|
|
39
|
+
await AsyncStorage.setItem(this.makeKey(k), JSON.stringify(v));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async removeItem(k: string): Promise<void> {
|
|
43
|
+
await AsyncStorage.removeItem(this.makeKey(k));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async getAllKeys(): Promise<string[]> {
|
|
47
|
+
const allKeys = await AsyncStorage.getAllKeys();
|
|
48
|
+
const keys: string[] = [];
|
|
49
|
+
const keyPrefix = this.makeKey('');
|
|
50
|
+
for (const key of allKeys) {
|
|
51
|
+
if (key.startsWith(keyPrefix)) {
|
|
52
|
+
keys.push(key.substring(keyPrefix.length));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return keys;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async multiSet(keyValuePairs: Array<[string, any]>): Promise<void> {
|
|
59
|
+
await AsyncStorage.multiSet(
|
|
60
|
+
keyValuePairs.map(([k, v]) => [this.makeKey(k), JSON.stringify(v)]),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class MissingStore extends StoreInterface {
|
|
66
|
+
constructor(appId: string, dbName: StoreInterfaceStoreName) {
|
|
67
|
+
super(appId, dbName);
|
|
68
|
+
throw new Error(
|
|
69
|
+
'Instant needs a store to persist data on device. ' +
|
|
70
|
+
'Install `@react-native-async-storage/async-storage`, ' +
|
|
71
|
+
'or pass a `Store` to `init` (e.g. from `@instantdb/react-native-mmkv` or `@instantdb/expo-sqlite`).' +
|
|
72
|
+
(asyncStorageLoadError
|
|
73
|
+
? `\n\nLoading async-storage failed with: ${asyncStorageLoadError}`
|
|
74
|
+
: ''),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async getItem(_k: string): Promise<any> {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async removeItem(_k: string): Promise<void> {}
|
|
83
|
+
|
|
84
|
+
async multiSet(_keyValuePairs: Array<[string, any]>): Promise<void> {}
|
|
85
|
+
|
|
86
|
+
async getAllKeys(): Promise<string[]> {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default AsyncStorage ? AsyncStorageStore : MissingStore;
|
package/src/Streams.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Type testing utils from
|
|
2
|
+
// https://github.com/type-challenges/type-challenges/blob/main/utils/index.d.ts
|
|
3
|
+
|
|
4
|
+
export type Expect<T extends true> = T;
|
|
5
|
+
export type ExpectTrue<T extends true> = T;
|
|
6
|
+
export type ExpectFalse<T extends false> = T;
|
|
7
|
+
export type IsTrue<T extends true> = T;
|
|
8
|
+
export type IsFalse<T extends false> = T;
|
|
9
|
+
|
|
10
|
+
export type Equal<X, Y> =
|
|
11
|
+
(<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
|
12
|
+
? true
|
|
13
|
+
: false;
|
|
14
|
+
export type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true;
|
|
15
|
+
|
|
16
|
+
// https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
|
|
17
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
18
|
+
export type NotAny<T> = true extends IsAny<T> ? false : true;
|
|
19
|
+
|
|
20
|
+
export type Debug<T> = { [K in keyof T]: T[K] };
|
|
21
|
+
export type MergeInsertions<T> = T extends object
|
|
22
|
+
? { [K in keyof T]: MergeInsertions<T[K]> }
|
|
23
|
+
: T;
|
|
24
|
+
|
|
25
|
+
export type Alike<X, Y> = Equal<MergeInsertions<X>, MergeInsertions<Y>>;
|
|
26
|
+
|
|
27
|
+
export type ExpectExtends<VALUE, EXPECTED> = EXPECTED extends VALUE
|
|
28
|
+
? true
|
|
29
|
+
: false;
|
|
30
|
+
export type ExpectValidArgs<
|
|
31
|
+
FUNC extends (...args: any[]) => any,
|
|
32
|
+
ARGS extends any[],
|
|
33
|
+
> = ARGS extends Parameters<FUNC> ? true : false;
|
|
34
|
+
|
|
35
|
+
export type UnionToIntersection<U> = (
|
|
36
|
+
U extends any ? (k: U) => void : never
|
|
37
|
+
) extends (k: infer I) => void
|
|
38
|
+
? I
|
|
39
|
+
: never;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Equal, Expect, IsAny, NotAny } from './typeUtils';
|
|
2
|
+
import { i, init } from '../index';
|
|
3
|
+
|
|
4
|
+
const schema = i.schema({
|
|
5
|
+
entities: {
|
|
6
|
+
tbl: i.entity({
|
|
7
|
+
d: i.date().indexed(),
|
|
8
|
+
dOptional: i.date().optional(),
|
|
9
|
+
}),
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
function _testUseDatesTest() {
|
|
14
|
+
const db = init({
|
|
15
|
+
schema,
|
|
16
|
+
appId: '123',
|
|
17
|
+
useDateObjects: true,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const { data } = db.useQuery({ tbl: {} });
|
|
21
|
+
const item = data?.tbl[0];
|
|
22
|
+
if (item) {
|
|
23
|
+
type t = typeof item.d;
|
|
24
|
+
type _cases = [Expect<NotAny<t>>, Expect<Equal<t, Date>>];
|
|
25
|
+
|
|
26
|
+
type tOpt = typeof item.dOptional;
|
|
27
|
+
type _cases_2 = [
|
|
28
|
+
Expect<NotAny<tOpt>>,
|
|
29
|
+
Expect<Equal<tOpt, Date | undefined>>,
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _testUseDatesFalseTest() {
|
|
35
|
+
const db = init({
|
|
36
|
+
schema,
|
|
37
|
+
appId: '123',
|
|
38
|
+
useDateObjects: false,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const { data } = db.useQuery({ tbl: {} });
|
|
42
|
+
const item = data?.tbl[0];
|
|
43
|
+
if (item) {
|
|
44
|
+
type t = typeof item.d;
|
|
45
|
+
type _cases = [Expect<NotAny<t>>, Expect<Equal<t, string | number>>];
|
|
46
|
+
|
|
47
|
+
type tOpt = typeof item.dOptional;
|
|
48
|
+
type _cases_2 = [
|
|
49
|
+
Expect<NotAny<tOpt>>,
|
|
50
|
+
Expect<Equal<tOpt, string | number | undefined>>,
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function _testUseDatesUndefinedTest() {
|
|
56
|
+
const db = init({
|
|
57
|
+
schema,
|
|
58
|
+
appId: '123',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const { data } = db.useQuery({ tbl: {} });
|
|
62
|
+
const item = data?.tbl[0];
|
|
63
|
+
if (item) {
|
|
64
|
+
type t = typeof item.d;
|
|
65
|
+
type _cases = [Expect<NotAny<t>>, Expect<Equal<t, string | number>>];
|
|
66
|
+
|
|
67
|
+
type tOpt = typeof item.dOptional;
|
|
68
|
+
type _cases_2 = [
|
|
69
|
+
Expect<NotAny<tOpt>>,
|
|
70
|
+
Expect<Equal<tOpt, string | number | undefined>>,
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function _testDataNoSchema() {
|
|
76
|
+
const db = init({
|
|
77
|
+
appId: '123',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const { data } = db.useQuery({ tbl: {} });
|
|
81
|
+
const item = data?.tbl[0];
|
|
82
|
+
if (item) {
|
|
83
|
+
type t = typeof item.d;
|
|
84
|
+
type _cases = [Expect<IsAny<t>>, Expect<Equal<typeof item.id, string>>];
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@fidscript/instant-sdk';
|