zitejs 0.9.90 → 0.9.92

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.
@@ -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,26 @@ 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 target = new URL(opts?.redirectUrl ?? window.location.href, window.location.href);
46
+ // Say nothing when there's nothing to say. The sign-in page already returns
47
+ // people to the app root when it isn't told otherwise, so naming the root
48
+ // spells out the default — and puts an encoded copy of the app's own URL in
49
+ // the address bar of every logged-out visitor to the front page, which is the
50
+ // common case. Only pass a destination when it IS one.
51
+ const isRoot = target.pathname === '/' && target.search === '' && target.hash === '';
52
+ window.location.href = isRoot
53
+ ? '/auth/login'
54
+ : '/auth/login?' +
55
+ new URLSearchParams({ redirectUrl: target.toString() }).toString();
43
56
  }
44
57
  function logout(opts) {
45
58
  (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,69 @@ 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)('says nothing when the destination is the app root', () => {
87
+ // The sign-in page already returns people to the root, so naming it would
88
+ // just put an encoded copy of the app's own URL in the address bar — and a
89
+ // logged-out visitor to the front page is the common case.
90
+ const location = stubLocation('https://app.zite.so/');
91
+ authExports.loginWithRedirect();
92
+ (0, vitest_1.expect)(location.href).toBe('/auth/login');
93
+ });
94
+ (0, vitest_1.it)('says nothing when an explicit redirectUrl is the app root', () => {
95
+ const location = stubLocation('https://app.zite.so/pricing');
96
+ authExports.loginWithRedirect({ redirectUrl: '/' });
97
+ (0, vitest_1.expect)(location.href).toBe('/auth/login');
98
+ });
99
+ (0, vitest_1.it)('still names a root path that carries a query or hash', () => {
100
+ const location = stubLocation('https://app.zite.so/?invite=abc');
101
+ authExports.loginWithRedirect();
102
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/?invite=abc');
103
+ });
104
+ (0, vitest_1.it)('captures the current URL when called with no arguments', () => {
105
+ const location = stubLocation('https://app.zite.so/orders/123?tab=open');
106
+ authExports.loginWithRedirect();
107
+ (0, vitest_1.expect)(location.href.startsWith('/auth/login?')).toBe(true);
108
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/orders/123?tab=open');
109
+ });
110
+ (0, vitest_1.it)('round-trips a path better-auth would reject in relative form', () => {
111
+ // Encoded spaces and fragments fail better-auth's relative-callbackURL
112
+ // regex. Sending the absolute URL sidesteps that check entirely, so the
113
+ // deep link survives instead of 403ing at verify time.
114
+ const href = 'https://app.zite.so/items/hello%20world#row-3';
115
+ const location = stubLocation(href);
116
+ authExports.loginWithRedirect();
117
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe(href);
118
+ });
119
+ (0, vitest_1.it)('lets an explicit redirectUrl override the current URL', () => {
120
+ const location = stubLocation('https://app.zite.so/pricing');
121
+ authExports.loginWithRedirect({
122
+ redirectUrl: 'https://app.zite.so/dashboard',
123
+ });
124
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
125
+ });
126
+ (0, vitest_1.it)('resolves a relative override against the current origin', () => {
127
+ // Callers shouldn't have to know that better-auth treats relative and
128
+ // absolute callbackURLs differently — whichever form reads best in app code
129
+ // leaves here absolute.
130
+ const location = stubLocation('https://app.zite.so/pricing');
131
+ authExports.loginWithRedirect({ redirectUrl: '/dashboard' });
132
+ (0, vitest_1.expect)(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
133
+ });
134
+ (0, vitest_1.it)('is a no-op on the auth page, so it cannot capture itself', () => {
135
+ const href = 'https://app.zite.so/auth/login?redirectUrl=%2Forders';
136
+ const location = stubLocation(href);
137
+ authExports.loginWithRedirect();
138
+ (0, vitest_1.expect)(location.href).toBe(href);
139
+ });
140
+ (0, vitest_1.it)('accepts the deprecated initialView without emitting it', () => {
141
+ // App source predating the one-door sign-in still passes this. Dropping it
142
+ // from the type would fail those apps' next typecheck, and a typecheck error
143
+ // fails the build — so it stays accepted, and stays ignored.
144
+ const location = stubLocation('https://app.zite.so/pricing');
145
+ authExports.loginWithRedirect({ initialView: 'signup' });
146
+ const params = new URLSearchParams(location.href.split('?')[1] ?? '');
147
+ (0, vitest_1.expect)(params.get('view')).toBeNull();
148
+ (0, vitest_1.expect)(params.get('redirectUrl')).toBe('https://app.zite.so/pricing');
149
+ });
150
+ });
@@ -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,26 @@ 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 target = new URL(opts?.redirectUrl ?? window.location.href, window.location.href);
39
+ // Say nothing when there's nothing to say. The sign-in page already returns
40
+ // people to the app root when it isn't told otherwise, so naming the root
41
+ // spells out the default — and puts an encoded copy of the app's own URL in
42
+ // the address bar of every logged-out visitor to the front page, which is the
43
+ // common case. Only pass a destination when it IS one.
44
+ const isRoot = target.pathname === '/' && target.search === '' && target.hash === '';
45
+ window.location.href = isRoot
46
+ ? '/auth/login'
47
+ : '/auth/login?' +
48
+ new URLSearchParams({ redirectUrl: target.toString() }).toString();
36
49
  }
37
50
  export function logout(opts) {
38
51
  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,69 @@ describe('zitejs/auth exports', () => {
30
47
  expect(typeof authExports.updateProfile).toBe('function');
31
48
  });
32
49
  });
50
+ describe('loginWithRedirect', () => {
51
+ it('says nothing when the destination is the app root', () => {
52
+ // The sign-in page already returns people to the root, so naming it would
53
+ // just put an encoded copy of the app's own URL in the address bar — and a
54
+ // logged-out visitor to the front page is the common case.
55
+ const location = stubLocation('https://app.zite.so/');
56
+ authExports.loginWithRedirect();
57
+ expect(location.href).toBe('/auth/login');
58
+ });
59
+ it('says nothing when an explicit redirectUrl is the app root', () => {
60
+ const location = stubLocation('https://app.zite.so/pricing');
61
+ authExports.loginWithRedirect({ redirectUrl: '/' });
62
+ expect(location.href).toBe('/auth/login');
63
+ });
64
+ it('still names a root path that carries a query or hash', () => {
65
+ const location = stubLocation('https://app.zite.so/?invite=abc');
66
+ authExports.loginWithRedirect();
67
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/?invite=abc');
68
+ });
69
+ it('captures the current URL when called with no arguments', () => {
70
+ const location = stubLocation('https://app.zite.so/orders/123?tab=open');
71
+ authExports.loginWithRedirect();
72
+ expect(location.href.startsWith('/auth/login?')).toBe(true);
73
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/orders/123?tab=open');
74
+ });
75
+ it('round-trips a path better-auth would reject in relative form', () => {
76
+ // Encoded spaces and fragments fail better-auth's relative-callbackURL
77
+ // regex. Sending the absolute URL sidesteps that check entirely, so the
78
+ // deep link survives instead of 403ing at verify time.
79
+ const href = 'https://app.zite.so/items/hello%20world#row-3';
80
+ const location = stubLocation(href);
81
+ authExports.loginWithRedirect();
82
+ expect(redirectParamOf(location.href)).toBe(href);
83
+ });
84
+ it('lets an explicit redirectUrl override the current URL', () => {
85
+ const location = stubLocation('https://app.zite.so/pricing');
86
+ authExports.loginWithRedirect({
87
+ redirectUrl: 'https://app.zite.so/dashboard',
88
+ });
89
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
90
+ });
91
+ it('resolves a relative override against the current origin', () => {
92
+ // Callers shouldn't have to know that better-auth treats relative and
93
+ // absolute callbackURLs differently — whichever form reads best in app code
94
+ // leaves here absolute.
95
+ const location = stubLocation('https://app.zite.so/pricing');
96
+ authExports.loginWithRedirect({ redirectUrl: '/dashboard' });
97
+ expect(redirectParamOf(location.href)).toBe('https://app.zite.so/dashboard');
98
+ });
99
+ it('is a no-op on the auth page, so it cannot capture itself', () => {
100
+ const href = 'https://app.zite.so/auth/login?redirectUrl=%2Forders';
101
+ const location = stubLocation(href);
102
+ authExports.loginWithRedirect();
103
+ expect(location.href).toBe(href);
104
+ });
105
+ it('accepts the deprecated initialView without emitting it', () => {
106
+ // App source predating the one-door sign-in still passes this. Dropping it
107
+ // from the type would fail those apps' next typecheck, and a typecheck error
108
+ // fails the build — so it stays accepted, and stays ignored.
109
+ const location = stubLocation('https://app.zite.so/pricing');
110
+ authExports.loginWithRedirect({ initialView: 'signup' });
111
+ const params = new URLSearchParams(location.href.split('?')[1] ?? '');
112
+ expect(params.get('view')).toBeNull();
113
+ expect(params.get('redirectUrl')).toBe('https://app.zite.so/pricing');
114
+ });
115
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zitejs",
3
- "version": "0.9.90",
3
+ "version": "0.9.92",
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;