zitejs 0.9.89 → 0.9.91

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 CHANGED
@@ -11,6 +11,7 @@ const contacts = await zite.contacts.findAll();
11
11
 
12
12
  // Query and update Zite auth users from backend endpoints
13
13
  const { records: users } = await zite.auth.findAllUsers({
14
+ appIds: ['app-1'],
14
15
  filters: { email: 'person@example.com' },
15
16
  });
16
17
  await zite.auth.updateUserProfile(users[0].id, {
@@ -209,6 +209,12 @@ export declare const signUp: {
209
209
  };
210
210
  export declare function loginWithRedirect(opts?: {
211
211
  redirectUrl?: string;
212
+ /**
213
+ * @deprecated Ignored. There is one sign-in screen now — the server works out
214
+ * from the email whether it's a sign-in or a sign-up. Still accepted, because
215
+ * app source written before that change would otherwise stop typechecking on
216
+ * its next build, and a typecheck error fails the build outright.
217
+ */
212
218
  initialView?: 'login' | 'signup';
213
219
  }): void;
214
220
  export declare function logout(opts?: {
@@ -33,13 +33,18 @@ exports.signUp = authClient.signUp;
33
33
  function loginWithRedirect(opts) {
34
34
  if (window.location.pathname.startsWith('/auth/'))
35
35
  return;
36
- const params = new URLSearchParams();
37
- if (opts?.redirectUrl)
38
- params.set('redirectUrl', opts.redirectUrl);
39
- if (opts?.initialView)
40
- params.set('view', opts.initialView);
41
- const query = params.toString();
42
- window.location.href = '/auth/login' + (query ? '?' + query : '');
36
+ // Default to wherever the user already is, so a deep link survives the round
37
+ // trip through login without every app having to remember to pass it. Pass
38
+ // `redirectUrl` only to send them somewhere else instead.
39
+ //
40
+ // Resolved to an absolute URL either way, on purpose: better-auth
41
+ // character-checks a *relative* callbackURL — an encoded space, a fragment or
42
+ // any non-ASCII in the path fails its regex and the destination is dropped —
43
+ // but never inspects the path of an absolute one. Normalising here means a
44
+ // caller can pass whichever form reads best without having to know that.
45
+ const redirectUrl = new URL(opts?.redirectUrl ?? window.location.href, window.location.href).toString();
46
+ window.location.href =
47
+ '/auth/login?' + new URLSearchParams({ redirectUrl }).toString();
43
48
  }
44
49
  function logout(opts) {
45
50
  (0, exports.signOut)().then(() => {
@@ -35,6 +35,23 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const vitest_1 = require("vitest");
37
37
  const authExports = __importStar(require("./index.js"));
38
+ /**
39
+ * `loginWithRedirect` navigates the browser; the test env is node, so stand up
40
+ * the only two bits of `window` it touches. Assigning `href` on a plain object
41
+ * is enough — all we care about is where it tried to go.
42
+ */
43
+ function stubLocation(href) {
44
+ const location = { pathname: new URL(href).pathname, href };
45
+ vitest_1.vi.stubGlobal('window', { location });
46
+ return location;
47
+ }
48
+ /** What the receiving end (`/auth/login`) will actually read back out. */
49
+ function redirectParamOf(href) {
50
+ return new URLSearchParams(href.split('?')[1] ?? '').get('redirectUrl');
51
+ }
52
+ (0, vitest_1.afterEach)(() => {
53
+ vitest_1.vi.unstubAllGlobals();
54
+ });
38
55
  (0, vitest_1.describe)('zitejs/auth exports', () => {
39
56
  (0, vitest_1.it)('exports loginWithRedirect as a function', () => {
40
57
  (0, vitest_1.expect)(typeof authExports.loginWithRedirect).toBe('function');
@@ -65,3 +82,51 @@ const authExports = __importStar(require("./index.js"));
65
82
  (0, vitest_1.expect)(typeof authExports.updateProfile).toBe('function');
66
83
  });
67
84
  });
85
+ (0, vitest_1.describe)('loginWithRedirect', () => {
86
+ (0, vitest_1.it)('captures the current URL when called with no arguments', () => {
87
+ const location = stubLocation('https://app.zite.so/orders/123?tab=open');
88
+ authExports.loginWithRedirect();
89
+ (0, vitest_1.expect)(location.href.startsWith('/auth/login?')).toBe(true);
90
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/orders/123?tab=open');
91
+ });
92
+ (0, vitest_1.it)('round-trips a path better-auth would reject in relative form', () => {
93
+ // Encoded spaces and fragments fail better-auth's relative-callbackURL
94
+ // regex. Sending the absolute URL sidesteps that check entirely, so the
95
+ // deep link survives instead of 403ing at verify time.
96
+ const href = 'https://app.zite.so/items/hello%20world#row-3';
97
+ const location = stubLocation(href);
98
+ authExports.loginWithRedirect();
99
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe(href);
100
+ });
101
+ (0, vitest_1.it)('lets an explicit redirectUrl override the current URL', () => {
102
+ const location = stubLocation('https://app.zite.so/pricing');
103
+ authExports.loginWithRedirect({
104
+ redirectUrl: 'https://app.zite.so/dashboard',
105
+ });
106
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
107
+ });
108
+ (0, vitest_1.it)('resolves a relative override against the current origin', () => {
109
+ // Callers shouldn't have to know that better-auth treats relative and
110
+ // absolute callbackURLs differently — whichever form reads best in app code
111
+ // leaves here absolute.
112
+ const location = stubLocation('https://app.zite.so/pricing');
113
+ authExports.loginWithRedirect({ redirectUrl: '/dashboard' });
114
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
115
+ });
116
+ (0, vitest_1.it)('is a no-op on the auth page, so it cannot capture itself', () => {
117
+ const href = 'https://app.zite.so/auth/login?redirectUrl=%2Forders';
118
+ const location = stubLocation(href);
119
+ authExports.loginWithRedirect();
120
+ (0, vitest_1.expect)(location.href).toBe(href);
121
+ });
122
+ (0, vitest_1.it)('accepts the deprecated initialView without emitting it', () => {
123
+ // App source predating the one-door sign-in still passes this. Dropping it
124
+ // from the type would fail those apps' next typecheck, and a typecheck error
125
+ // fails the build — so it stays accepted, and stays ignored.
126
+ const location = stubLocation('https://app.zite.so/pricing');
127
+ authExports.loginWithRedirect({ initialView: 'signup' });
128
+ const params = new URLSearchParams(location.href.split('?')[1] ?? '');
129
+ (0, vitest_1.expect)(params.get('view')).toBeNull();
130
+ (0, vitest_1.expect)(params.get('redirectUrl')).toBe('https://app.zite.so/pricing');
131
+ });
132
+ });
@@ -65,7 +65,10 @@ export interface AuthUser {
65
65
  lastName: string | null;
66
66
  image: string | null;
67
67
  }
68
- export type FindAllAuthUsersOptions = Omit<TableFindAllOptions, "fields">;
68
+ export type FindAllAuthUsersOptions = Omit<TableFindAllOptions, "fields"> & {
69
+ /** Restrict results to users belonging to any of these apps. */
70
+ appIds?: string[];
71
+ };
69
72
  export type FindAllAuthUsersResult<T extends AuthUser = AuthUser> = {
70
73
  records: T[];
71
74
  total: number;
@@ -330,8 +330,9 @@ function generateDbTs(schema) {
330
330
  lines.push("// .bulkCreate({ records, matchOn? }) → { success: boolean, records: T[] }");
331
331
  lines.push("//");
332
332
  lines.push("// Zite auth users:");
333
- lines.push("// zite.auth.findAllUsers({ filter?, filters?, sort?, limit?, offset? })");
333
+ lines.push("// zite.auth.findAllUsers({ appIds?, filter?, filters?, sort?, limit?, offset? })");
334
334
  lines.push("// Supports the same filter, sort, and pagination options as table .findAll()");
335
+ lines.push("// appIds restricts results to users belonging to any listed app");
335
336
  lines.push("// zite.auth.updateUserProfile(userId, { firstName?, lastName?, image? })");
336
337
  lines.push("// User email addresses cannot be updated through this API");
337
338
  lines.push("//");
@@ -209,6 +209,12 @@ export declare const signUp: {
209
209
  };
210
210
  export declare function loginWithRedirect(opts?: {
211
211
  redirectUrl?: string;
212
+ /**
213
+ * @deprecated Ignored. There is one sign-in screen now — the server works out
214
+ * from the email whether it's a sign-in or a sign-up. Still accepted, because
215
+ * app source written before that change would otherwise stop typechecking on
216
+ * its next build, and a typecheck error fails the build outright.
217
+ */
212
218
  initialView?: 'login' | 'signup';
213
219
  }): void;
214
220
  export declare function logout(opts?: {
@@ -26,13 +26,18 @@ export const signUp = authClient.signUp;
26
26
  export function loginWithRedirect(opts) {
27
27
  if (window.location.pathname.startsWith('/auth/'))
28
28
  return;
29
- const params = new URLSearchParams();
30
- if (opts?.redirectUrl)
31
- params.set('redirectUrl', opts.redirectUrl);
32
- if (opts?.initialView)
33
- params.set('view', opts.initialView);
34
- const query = params.toString();
35
- window.location.href = '/auth/login' + (query ? '?' + query : '');
29
+ // Default to wherever the user already is, so a deep link survives the round
30
+ // trip through login without every app having to remember to pass it. Pass
31
+ // `redirectUrl` only to send them somewhere else instead.
32
+ //
33
+ // Resolved to an absolute URL either way, on purpose: better-auth
34
+ // character-checks a *relative* callbackURL — an encoded space, a fragment or
35
+ // any non-ASCII in the path fails its regex and the destination is dropped —
36
+ // but never inspects the path of an absolute one. Normalising here means a
37
+ // caller can pass whichever form reads best without having to know that.
38
+ const redirectUrl = new URL(opts?.redirectUrl ?? window.location.href, window.location.href).toString();
39
+ window.location.href =
40
+ '/auth/login?' + new URLSearchParams({ redirectUrl }).toString();
36
41
  }
37
42
  export function logout(opts) {
38
43
  signOut().then(() => {
@@ -1,5 +1,22 @@
1
- import { describe, it, expect } from 'vitest';
1
+ import { describe, it, expect, afterEach, vi } from 'vitest';
2
2
  import * as authExports from './index.js';
3
+ /**
4
+ * `loginWithRedirect` navigates the browser; the test env is node, so stand up
5
+ * the only two bits of `window` it touches. Assigning `href` on a plain object
6
+ * is enough — all we care about is where it tried to go.
7
+ */
8
+ function stubLocation(href) {
9
+ const location = { pathname: new URL(href).pathname, href };
10
+ vi.stubGlobal('window', { location });
11
+ return location;
12
+ }
13
+ /** What the receiving end (`/auth/login`) will actually read back out. */
14
+ function redirectParamOf(href) {
15
+ return new URLSearchParams(href.split('?')[1] ?? '').get('redirectUrl');
16
+ }
17
+ afterEach(() => {
18
+ vi.unstubAllGlobals();
19
+ });
3
20
  describe('zitejs/auth exports', () => {
4
21
  it('exports loginWithRedirect as a function', () => {
5
22
  expect(typeof authExports.loginWithRedirect).toBe('function');
@@ -30,3 +47,51 @@ describe('zitejs/auth exports', () => {
30
47
  expect(typeof authExports.updateProfile).toBe('function');
31
48
  });
32
49
  });
50
+ describe('loginWithRedirect', () => {
51
+ it('captures the current URL when called with no arguments', () => {
52
+ const location = stubLocation('https://app.zite.so/orders/123?tab=open');
53
+ authExports.loginWithRedirect();
54
+ expect(location.href.startsWith('/auth/login?')).toBe(true);
55
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/orders/123?tab=open');
56
+ });
57
+ it('round-trips a path better-auth would reject in relative form', () => {
58
+ // Encoded spaces and fragments fail better-auth's relative-callbackURL
59
+ // regex. Sending the absolute URL sidesteps that check entirely, so the
60
+ // deep link survives instead of 403ing at verify time.
61
+ const href = 'https://app.zite.so/items/hello%20world#row-3';
62
+ const location = stubLocation(href);
63
+ authExports.loginWithRedirect();
64
+ expect(redirectParamOf(location.href)).toBe(href);
65
+ });
66
+ it('lets an explicit redirectUrl override the current URL', () => {
67
+ const location = stubLocation('https://app.zite.so/pricing');
68
+ authExports.loginWithRedirect({
69
+ redirectUrl: 'https://app.zite.so/dashboard',
70
+ });
71
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
72
+ });
73
+ it('resolves a relative override against the current origin', () => {
74
+ // Callers shouldn't have to know that better-auth treats relative and
75
+ // absolute callbackURLs differently — whichever form reads best in app code
76
+ // leaves here absolute.
77
+ const location = stubLocation('https://app.zite.so/pricing');
78
+ authExports.loginWithRedirect({ redirectUrl: '/dashboard' });
79
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
80
+ });
81
+ it('is a no-op on the auth page, so it cannot capture itself', () => {
82
+ const href = 'https://app.zite.so/auth/login?redirectUrl=%2Forders';
83
+ const location = stubLocation(href);
84
+ authExports.loginWithRedirect();
85
+ expect(location.href).toBe(href);
86
+ });
87
+ it('accepts the deprecated initialView without emitting it', () => {
88
+ // App source predating the one-door sign-in still passes this. Dropping it
89
+ // from the type would fail those apps' next typecheck, and a typecheck error
90
+ // fails the build — so it stays accepted, and stays ignored.
91
+ const location = stubLocation('https://app.zite.so/pricing');
92
+ authExports.loginWithRedirect({ initialView: 'signup' });
93
+ const params = new URLSearchParams(location.href.split('?')[1] ?? '');
94
+ expect(params.get('view')).toBeNull();
95
+ expect(params.get('redirectUrl')).toBe('https://app.zite.so/pricing');
96
+ });
97
+ });
@@ -65,7 +65,10 @@ export interface AuthUser {
65
65
  lastName: string | null;
66
66
  image: string | null;
67
67
  }
68
- export type FindAllAuthUsersOptions = Omit<TableFindAllOptions, "fields">;
68
+ export type FindAllAuthUsersOptions = Omit<TableFindAllOptions, "fields"> & {
69
+ /** Restrict results to users belonging to any of these apps. */
70
+ appIds?: string[];
71
+ };
69
72
  export type FindAllAuthUsersResult<T extends AuthUser = AuthUser> = {
70
73
  records: T[];
71
74
  total: number;
@@ -320,8 +320,9 @@ export function generateDbTs(schema) {
320
320
  lines.push("// .bulkCreate({ records, matchOn? }) → { success: boolean, records: T[] }");
321
321
  lines.push("//");
322
322
  lines.push("// Zite auth users:");
323
- lines.push("// zite.auth.findAllUsers({ filter?, filters?, sort?, limit?, offset? })");
323
+ lines.push("// zite.auth.findAllUsers({ appIds?, filter?, filters?, sort?, limit?, offset? })");
324
324
  lines.push("// Supports the same filter, sort, and pagination options as table .findAll()");
325
+ lines.push("// appIds restricts results to users belonging to any listed app");
325
326
  lines.push("// zite.auth.updateUserProfile(userId, { firstName?, lastName?, image? })");
326
327
  lines.push("// User email addresses cannot be updated through this API");
327
328
  lines.push("//");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zitejs",
3
- "version": "0.9.89",
3
+ "version": "0.9.91",
4
4
  "description": "The Zite framework — build apps on Zite Database",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -1,14 +0,0 @@
1
- export type ZiteProjectUser = {
2
- uuid: string;
3
- firstName: string | null;
4
- lastName: string | null;
5
- email: string;
6
- profilePictureUrl: string | null;
7
- };
8
- export type MetaListUsersResult = {
9
- users: ZiteProjectUser[];
10
- };
11
- export declare class ZiteMeta {
12
- static listUsers(): Promise<MetaListUsersResult>;
13
- }
14
- export declare const Meta: typeof ZiteMeta;
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Meta = exports.ZiteMeta = void 0;
4
- const sdkCall_js_1 = require("../internal/sdkCall.js");
5
- const META_SDK_INTEGRATION_ID = '__meta__';
6
- class ZiteMeta {
7
- static listUsers() {
8
- return (0, sdkCall_js_1.getSdkCall)()(META_SDK_INTEGRATION_ID, 'ZiteMeta', 'listUsers', {});
9
- }
10
- }
11
- exports.ZiteMeta = ZiteMeta;
12
- exports.Meta = ZiteMeta;
@@ -1,14 +0,0 @@
1
- export type ZiteProjectUser = {
2
- uuid: string;
3
- firstName: string | null;
4
- lastName: string | null;
5
- email: string;
6
- profilePictureUrl: string | null;
7
- };
8
- export type MetaListUsersResult = {
9
- users: ZiteProjectUser[];
10
- };
11
- export declare class ZiteMeta {
12
- static listUsers(): Promise<MetaListUsersResult>;
13
- }
14
- export declare const Meta: typeof ZiteMeta;
@@ -1,8 +0,0 @@
1
- import { getSdkCall } from '../internal/sdkCall.js';
2
- const META_SDK_INTEGRATION_ID = '__meta__';
3
- export class ZiteMeta {
4
- static listUsers() {
5
- return getSdkCall()(META_SDK_INTEGRATION_ID, 'ZiteMeta', 'listUsers', {});
6
- }
7
- }
8
- export const Meta = ZiteMeta;