@object-ui/data-objectstack 17.5.0 → 17.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +219 -0
  2. package/dist/index.cjs +262 -357
  3. package/dist/index.d.cts +385 -448
  4. package/dist/index.d.ts +385 -448
  5. package/dist/index.js +258 -350
  6. package/package.json +5 -6
  7. package/dist/tsconfig.tsbuildinfo +0 -1
  8. package/src/aggregate-capability.test.ts +0 -177
  9. package/src/apiAccessDenied.test.ts +0 -233
  10. package/src/appAccessProbe.test.ts +0 -147
  11. package/src/bulkDelete.test.ts +0 -75
  12. package/src/bulkUpdate.test.ts +0 -93
  13. package/src/cache/MetadataCache.test.ts +0 -477
  14. package/src/cache/MetadataCache.ts +0 -289
  15. package/src/cloud-surface-retired-4152.pin.test.ts +0 -171
  16. package/src/connection.test.ts +0 -188
  17. package/src/contracts.ts +0 -115
  18. package/src/deleteView.homes.test.ts +0 -389
  19. package/src/deleteViewContract.types.test.ts +0 -246
  20. package/src/errors.test.ts +0 -426
  21. package/src/errors.ts +0 -293
  22. package/src/exportDownload.test.ts +0 -141
  23. package/src/filter-entry-translation.test.ts +0 -360
  24. package/src/filter-operator-ast-parity.test.ts +0 -135
  25. package/src/getObjectSchema.test.ts +0 -145
  26. package/src/httpFailureLogging.test.ts +0 -109
  27. package/src/importJob.test.ts +0 -71
  28. package/src/index.ts +0 -4442
  29. package/src/integration.ts +0 -200
  30. package/src/listViewOverrides.test.ts +0 -241
  31. package/src/listViews.test.ts +0 -175
  32. package/src/metadata-client.get-envelope.test.ts +0 -171
  33. package/src/metadata-client.saveAdvisories.test.ts +0 -226
  34. package/src/metadata-client.test.ts +0 -303
  35. package/src/metadata-client.ts +0 -1046
  36. package/src/occ.test.ts +0 -101
  37. package/src/onMutation.test.ts +0 -589
  38. package/src/onSaveAdvisory.test.ts +0 -311
  39. package/src/onWriteWarning.test.ts +0 -273
  40. package/src/orderby-serialization.test.ts +0 -115
  41. package/src/queryDataset.test.ts +0 -543
  42. package/src/searchAll.test.ts +0 -120
  43. package/src/security.ts +0 -243
  44. package/src/spec-symbol-batch6.test.ts +0 -326
  45. package/src/studio.ts +0 -152
  46. package/src/updateView.draft.test.ts +0 -242
  47. package/src/userState.test.ts +0 -315
  48. package/src/userState.ts +0 -238
  49. package/src/v3-compat.test.ts +0 -229
  50. package/src/validation-error.test.ts +0 -94
  51. package/src/viewCacheInvalidation.pin.test.ts +0 -260
  52. package/src/viewInvalidationSeam.pin.test.ts +0 -162
@@ -1,109 +0,0 @@
1
- /**
2
- * objectui#4042 half 2 — a request failure must SAY which request failed.
3
- *
4
- * `@objectstack/client` reports every non-2xx as
5
- * `logger.error("HTTP request failed", undefined, { method, url, status, error })`.
6
- * The console's logger used to forward that verbatim, so the identifying
7
- * fields lived only in the third argument: anything that flattens a console
8
- * record to text rendered them `[object Object]` / `Object`, and a screenful of
9
- * failures told you nothing about which URL or which status. These tests pin
10
- * that the message string itself now carries method + url + status (+ code).
11
- */
12
-
13
- import { describe, it, expect, vi, afterEach } from 'vitest';
14
- import { formatHttpFailureMessage, createQuietHttpLogger } from './index';
15
-
16
- const META_401 = {
17
- method: 'GET',
18
- url: '/api/v1/meta/object',
19
- status: 401,
20
- error: { code: 'UNAUTHORIZED', message: 'Unauthorized' },
21
- };
22
-
23
- describe('formatHttpFailureMessage', () => {
24
- it('folds method, url and status into the message', () => {
25
- expect(formatHttpFailureMessage('HTTP request failed', META_401)).toBe(
26
- 'HTTP request failed: GET /api/v1/meta/object -> 401 [UNAUTHORIZED]',
27
- );
28
- });
29
-
30
- it('omits the code when the body carries none', () => {
31
- expect(
32
- formatHttpFailureMessage('HTTP request failed', {
33
- method: 'POST',
34
- url: '/api/v1/data/task',
35
- status: 500,
36
- }),
37
- ).toBe('HTTP request failed: POST /api/v1/data/task -> 500');
38
- });
39
-
40
- it('reads the `statusCode` spelling too', () => {
41
- expect(
42
- formatHttpFailureMessage('HTTP request failed', { url: '/api/v1/meta/app', statusCode: 403 }),
43
- ).toBe('HTTP request failed: GET /api/v1/meta/app -> 403');
44
- });
45
-
46
- it('returns null — not a husk — when meta identifies nothing', () => {
47
- expect(formatHttpFailureMessage('HTTP request failed', undefined)).toBeNull();
48
- expect(formatHttpFailureMessage('HTTP request failed', {})).toBeNull();
49
- expect(formatHttpFailureMessage('HTTP request failed', { error: { message: 'boom' } })).toBeNull();
50
- });
51
-
52
- it('never yields the un-diagnosable string the card reported', () => {
53
- const line = formatHttpFailureMessage('HTTP request failed', META_401)!;
54
- expect(line).not.toContain('[object Object]');
55
- expect(line).toContain('/api/v1/meta/object');
56
- expect(line).toContain('401');
57
- });
58
- });
59
-
60
- describe('createQuietHttpLogger', () => {
61
- afterEach(() => vi.restoreAllMocks());
62
-
63
- it('logs a 401 as an error whose FIRST argument identifies the request', () => {
64
- const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
65
- createQuietHttpLogger().error('HTTP request failed', undefined, META_401);
66
-
67
- expect(spy).toHaveBeenCalledTimes(1);
68
- const [message, , meta] = spy.mock.calls[0];
69
- expect(message).toBe('HTTP request failed: GET /api/v1/meta/object -> 401 [UNAUTHORIZED]');
70
- // The structured bag is still handed over for DevTools to expand — the
71
- // string is added alongside it, not instead of it.
72
- expect(meta).toEqual(META_401);
73
- });
74
-
75
- it('keeps demoting an expected 404, and identifies it in the demoted line too', () => {
76
- const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
77
- const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
78
-
79
- createQuietHttpLogger().error('HTTP request failed', undefined, {
80
- method: 'GET',
81
- url: '/api/v1/data/sys_presence',
82
- status: 404,
83
- error: { code: 'OBJECT_NOT_FOUND' },
84
- });
85
-
86
- expect(errorSpy).not.toHaveBeenCalled();
87
- expect(debugSpy).toHaveBeenCalledTimes(1);
88
- expect(debugSpy.mock.calls[0][0]).toContain('/api/v1/data/sys_presence -> 404');
89
- });
90
-
91
- it('does NOT silence a 401 — only 404-on-an-optional-collection is demoted', () => {
92
- const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
93
- const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
94
-
95
- // Session expiry mid-use: the console gates doomed requests, it does not
96
- // hide the ones that still fail.
97
- createQuietHttpLogger().error('HTTP request failed', undefined, META_401);
98
-
99
- expect(errorSpy).toHaveBeenCalledTimes(1);
100
- expect(debugSpy).not.toHaveBeenCalled();
101
- });
102
-
103
- it('falls back to the bare message when there is nothing to identify', () => {
104
- const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
105
- createQuietHttpLogger().error('Something broke', undefined, undefined);
106
-
107
- expect(spy.mock.calls[0][0]).toBe('Something broke');
108
- });
109
- });
@@ -1,71 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { describe, it, expect, vi } from 'vitest';
10
- import { ObjectStackAdapter } from './index';
11
-
12
- /**
13
- * Adapter over a mock client `data` namespace. The async import-job methods are
14
- * thin pass-throughs to the client SDK, so we assert delegation + argument
15
- * shaping, plus graceful degradation when the client lacks the job API.
16
- */
17
- function makeDS(stub: Record<string, any>) {
18
- const ds: any = new ObjectStackAdapter({
19
- baseUrl: 'http://test.local',
20
- fetch: vi.fn(async () => new Response(JSON.stringify({ success: true, data: { capabilities: {}, routes: {} } }), {
21
- status: 200,
22
- headers: { 'Content-Type': 'application/json' },
23
- })),
24
- });
25
- ds.connected = true;
26
- ds.connectionState = 'connected';
27
- ds.client = { data: stub };
28
- return ds;
29
- }
30
-
31
- describe('ObjectStackAdapter async import jobs', () => {
32
- it('createImportJob delegates to client.data.createImportJob', async () => {
33
- const createImportJob = vi.fn().mockResolvedValue({ jobId: 'imp_1', object: 'task', status: 'pending', total: 2 });
34
- const ds = makeDS({ createImportJob });
35
- const req = { format: 'json' as const, rows: [{ a: 1 }, { a: 2 }], writeMode: 'upsert' as const, matchFields: ['a'] };
36
- const res = await ds.createImportJob('task', req);
37
- expect(createImportJob).toHaveBeenCalledTimes(1);
38
- expect(createImportJob.mock.calls[0]).toEqual(['task', req]);
39
- expect(res).toMatchObject({ jobId: 'imp_1', status: 'pending', total: 2 });
40
- });
41
-
42
- it('getImportJobProgress / getImportJobResults / cancelImportJob delegate by jobId', async () => {
43
- const getImportJobProgress = vi.fn().mockResolvedValue({ jobId: 'imp_1', status: 'running', percentComplete: 50 });
44
- const getImportJobResults = vi.fn().mockResolvedValue({ jobId: 'imp_1', status: 'succeeded', results: [], resultsTruncated: false });
45
- const cancelImportJob = vi.fn().mockResolvedValue({ success: true });
46
- const ds = makeDS({ createImportJob: vi.fn(), getImportJobProgress, getImportJobResults, cancelImportJob });
47
-
48
- expect((await ds.getImportJobProgress('imp_1')).percentComplete).toBe(50);
49
- expect(getImportJobProgress).toHaveBeenCalledWith('imp_1');
50
-
51
- expect((await ds.getImportJobResults('imp_1')).resultsTruncated).toBe(false);
52
- expect(getImportJobResults).toHaveBeenCalledWith('imp_1');
53
-
54
- await ds.cancelImportJob('imp_1');
55
- expect(cancelImportJob).toHaveBeenCalledWith('imp_1');
56
- });
57
-
58
- it('listImportJobs forwards filters and returns the jobs array', async () => {
59
- const listImportJobs = vi.fn().mockResolvedValue([{ jobId: 'imp_1', object: 'task', status: 'succeeded' }]);
60
- const ds = makeDS({ createImportJob: vi.fn(), listImportJobs });
61
- const jobs = await ds.listImportJobs({ object: 'task', status: 'succeeded', limit: 10 });
62
- expect(listImportJobs).toHaveBeenCalledWith({ object: 'task', status: 'succeeded', limit: 10 });
63
- expect(jobs).toHaveLength(1);
64
- });
65
-
66
- it('throws UNSUPPORTED_OPERATION when the client lacks the job API', async () => {
67
- const ds = makeDS({ import: vi.fn() }); // sync import only, no createImportJob
68
- await expect(ds.createImportJob('task', { format: 'json', rows: [] })).rejects.toMatchObject({ code: 'UNSUPPORTED_OPERATION' });
69
- await expect(ds.getImportJobProgress('imp_1')).rejects.toMatchObject({ code: 'UNSUPPORTED_OPERATION' });
70
- });
71
- });