@jskit-ai/auth-web 0.1.159 → 0.1.161

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 (28) hide show
  1. package/package.json +29 -135
  2. package/patterns/auth-surface/PATTERN.md +84 -0
  3. package/patterns/auth-surface/example/.vibe64/bin/preview-identity +5 -0
  4. package/src/client/index.js +1 -4
  5. package/src/client/providers/AuthWebClientProvider.js +32 -60
  6. package/src/client/runtime/authClient.js +79 -0
  7. package/src/client/runtime/authGuardRuntime.js +28 -7
  8. package/src/server/AuthWebFeature.js +41 -0
  9. package/src/server/managedPreviewIdentity.js +344 -0
  10. package/src/server/services/AuthWebService.js +4 -16
  11. package/test/clientBoot.test.js +3 -3
  12. package/test/clientSurface.test.js +6 -16
  13. package/test/managedPreviewIdentity.test.js +89 -0
  14. package/test/packageMetadataOwnership.test.js +3 -15
  15. package/test/provider.test.js +30 -220
  16. package/test/providerRuntime.test.js +92 -307
  17. package/src/client/providers/bootAuthClientProvider.js +0 -49
  18. package/src/server/providers/AuthRouteServiceProvider.js +0 -31
  19. package/src/server/providers/AuthWebServiceProvider.js +0 -38
  20. /package/{templates → patterns/auth-surface/example}/src/pages/auth/login.vue +0 -0
  21. /package/{templates → patterns/auth-surface/example}/src/pages/auth/reset-password.vue +0 -0
  22. /package/{templates → patterns/auth-surface/example}/src/pages/auth/signout.vue +0 -0
  23. /package/{templates → patterns/auth-surface/example}/src/runtime/authGuardRuntime.js +0 -0
  24. /package/{templates → patterns/auth-surface/example}/src/runtime/authHttpClient.js +0 -0
  25. /package/{templates → patterns/auth-surface/example}/src/runtime/useSignOut.js +0 -0
  26. /package/{templates → patterns/auth-surface/example}/src/views/auth/LoginView.vue +0 -0
  27. /package/{templates → patterns/auth-surface/example}/src/views/auth/ResetPasswordView.vue +0 -0
  28. /package/{templates → patterns/auth-surface/example}/src/views/auth/SignOutView.vue +0 -0
@@ -1,240 +1,50 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
  import { createPinia } from "pinia";
4
- import {
5
- AUTH_GUARD_RUNTIME_INJECTION_KEY,
6
- AUTH_OAUTH_LAUNCH_CLIENT_INJECTION_KEY
7
- } from "../src/client/runtime/inject.js";
8
- import { bootAuthClientProvider } from "../src/client/providers/bootAuthClientProvider.js";
9
- import { useAuthStore } from "../src/client/stores/useAuthStore.js";
10
-
11
- function createAuthRuntimeStub(initialState = {}) {
12
- let state = Object.freeze({
13
- authenticated: Boolean(initialState.authenticated),
14
- username: String(initialState.username || ""),
15
- oauthDefaultProvider: String(initialState.oauthDefaultProvider || ""),
16
- oauthProviders: Array.isArray(initialState.oauthProviders)
17
- ? Object.freeze([...initialState.oauthProviders])
18
- : Object.freeze([])
19
- });
20
- let initializeCalls = 0;
21
- const listeners = new Set();
22
4
 
23
- return {
24
- async initialize() {
25
- initializeCalls += 1;
26
- return state;
27
- },
28
- async refresh() {
29
- return state;
30
- },
31
- getState() {
32
- return state;
33
- },
34
- subscribe(listener) {
35
- if (typeof listener === "function") {
36
- listeners.add(listener);
37
- }
38
- return () => {
39
- listeners.delete(listener);
40
- };
41
- },
42
- push(nextState = {}) {
43
- state = Object.freeze({
44
- authenticated: Boolean(nextState.authenticated),
45
- username: String(nextState.username || ""),
46
- oauthDefaultProvider: String(nextState.oauthDefaultProvider || ""),
47
- oauthProviders: Array.isArray(nextState.oauthProviders)
48
- ? Object.freeze([...nextState.oauthProviders])
49
- : Object.freeze([])
50
- });
51
-
52
- for (const listener of listeners) {
53
- listener(state);
54
- }
55
- },
56
- get initializeCalls() {
57
- return initializeCalls;
58
- }
59
- };
60
- }
61
-
62
- function createAppDouble({ authGuardRuntime, bootstrapRuntime = null, oauthLaunchClient = null } = {}) {
63
- const singletons = new Map();
64
- const singletonInstances = new Map();
65
- const provided = [];
66
- const pinia = createPinia();
67
- const vueApp = {
68
- provide(key, value) {
69
- provided.push({ key, value });
70
- }
71
- };
5
+ import {
6
+ createAuthClient,
7
+ createMobileCallbackCompleter
8
+ } from "../src/client/runtime/authClient.js";
72
9
 
10
+ function createShell() {
73
11
  return {
74
- singletons,
75
- provided,
76
- pinia,
77
- vueApp,
78
- singleton(token, factory) {
79
- singletons.set(token, factory);
80
- },
81
- has(token) {
82
- if (token === "jskit.client.vue.app") {
83
- return true;
84
- }
85
- if (token === "jskit.client.pinia") {
86
- return true;
87
- }
88
- if (token === "runtime.web-placement.client") {
89
- return true;
90
- }
91
- if (token === "runtime.auth-guard.client") {
92
- return true;
93
- }
94
- if (token === "runtime.web-bootstrap.client") {
95
- return Boolean(bootstrapRuntime);
96
- }
97
- if (token === "auth.oauth-launch.client") {
98
- return Boolean(oauthLaunchClient);
99
- }
100
- return singletons.has(token) || singletonInstances.has(token);
12
+ bootstrap: {
13
+ async refresh() {}
101
14
  },
102
- make(token) {
103
- if (token === "jskit.client.vue.app") {
104
- return vueApp;
105
- }
106
- if (token === "jskit.client.pinia") {
107
- return pinia;
108
- }
109
- if (token === "runtime.web-placement.client") {
15
+ placement: {
16
+ getContext() {
110
17
  return {
111
- getContext() {
112
- return Object.freeze({
113
- surfaceConfig: Object.freeze({
114
- enabledSurfaceIds: Object.freeze(["home"]),
115
- defaultSurfaceId: "home",
116
- surfaces: Object.freeze({
117
- home: Object.freeze({
118
- id: "home",
119
- origin: "",
120
- pagesRoot: "home"
121
- }),
122
- auth: Object.freeze({
123
- id: "auth",
124
- origin: "",
125
- pagesRoot: "auth"
126
- })
127
- })
128
- })
129
- });
18
+ surfaceConfig: {
19
+ defaultSurfaceId: "app",
20
+ enabledSurfaceIds: ["app", "auth"]
130
21
  }
131
22
  };
23
+ },
24
+ setContext() {
25
+ return this.getContext();
132
26
  }
133
- if (token === "runtime.auth-guard.client") {
134
- return authGuardRuntime;
135
- }
136
- if (token === "runtime.web-bootstrap.client") {
137
- return bootstrapRuntime;
138
- }
139
- if (token === "auth.oauth-launch.client") {
140
- return oauthLaunchClient;
141
- }
142
- if (singletonInstances.has(token)) {
143
- return singletonInstances.get(token);
144
- }
145
- const factory = singletons.get(token);
146
- if (!factory) {
147
- throw new Error(`Unknown token ${String(token)}`);
148
- }
149
- const instance = factory(this);
150
- singletonInstances.set(token, instance);
151
- return instance;
152
27
  }
153
28
  };
154
29
  }
155
30
 
156
- test("auth web client boot binds explicit Pinia store state and raw runtime injection together", async () => {
157
- const authGuardRuntime = createAuthRuntimeStub({
158
- authenticated: true,
159
- username: "ada"
160
- });
161
- const app = createAppDouble({ authGuardRuntime });
162
-
163
- await bootAuthClientProvider(app);
164
-
165
- const authStore = useAuthStore(app.pinia);
166
- assert.equal(authStore.runtime, authGuardRuntime);
167
- assert.equal(authStore.authenticated, true);
168
- assert.equal(authStore.username, "ada");
169
- assert.equal(authGuardRuntime.initializeCalls, 1);
170
-
171
- authGuardRuntime.push({
172
- authenticated: true,
173
- username: "grace"
174
- });
175
-
176
- assert.equal(authStore.username, "grace");
177
-
178
- const providedByKey = new Map(app.provided.map((entry) => [entry.key, entry.value]));
179
- assert.equal(providedByKey.get(AUTH_GUARD_RUNTIME_INJECTION_KEY), authGuardRuntime);
180
- assert.equal(typeof providedByKey.get(AUTH_OAUTH_LAUNCH_CLIENT_INJECTION_KEY)?.open, "function");
181
- });
182
-
183
- test("auth web client boot refreshes shared bootstrap runtime on auth changes", async () => {
184
- const authGuardRuntime = createAuthRuntimeStub({
185
- authenticated: false,
186
- username: ""
187
- });
188
- const refreshCalls = [];
189
- const app = createAppDouble({
190
- authGuardRuntime,
191
- bootstrapRuntime: {
192
- async refresh(reason) {
193
- refreshCalls.push(String(reason || ""));
194
- return null;
31
+ test("auth client groups guard, OAuth, and mobile callback behavior without a container", () => {
32
+ const provided = new Map();
33
+ const auth = createAuthClient({
34
+ pinia: createPinia(),
35
+ shell: createShell(),
36
+ vueApp: {
37
+ provide(key, value) {
38
+ provided.set(key, value);
195
39
  }
196
40
  }
197
41
  });
198
42
 
199
- await bootAuthClientProvider(app);
200
- assert.deepEqual(refreshCalls, []);
201
-
202
- authGuardRuntime.push({
203
- authenticated: true,
204
- username: "ada"
205
- });
206
-
207
- assert.deepEqual(refreshCalls, ["auth.state"]);
208
- });
209
-
210
- test("auth web client boot prefers an explicitly registered OAuth launch client", async () => {
211
- const authGuardRuntime = createAuthRuntimeStub({
212
- authenticated: false
213
- });
214
- const launchCalls = [];
215
- const oauthLaunchClient = {
216
- async open(input = {}) {
217
- launchCalls.push(input);
218
- return true;
219
- }
220
- };
221
- const app = createAppDouble({
222
- authGuardRuntime,
223
- oauthLaunchClient
224
- });
225
-
226
- await bootAuthClientProvider(app);
227
-
228
- const providedByKey = new Map(app.provided.map((entry) => [entry.key, entry.value]));
229
- const injectedLaunchClient = providedByKey.get(AUTH_OAUTH_LAUNCH_CLIENT_INJECTION_KEY);
230
- assert.equal(injectedLaunchClient, oauthLaunchClient);
231
-
232
- await injectedLaunchClient.open({
233
- url: "/api/oauth/google/start?returnTo=%2Fw%2Facme"
234
- });
235
- assert.deepEqual(launchCalls, [
236
- {
237
- url: "/api/oauth/google/start?returnTo=%2Fw%2Facme"
238
- }
239
- ]);
43
+ assert.equal(typeof auth.guard.initialize, "function");
44
+ assert.equal(typeof auth.oauthLaunch.open, "function");
45
+ assert.equal(typeof auth.mobileCallback.completeFromUrl, "function");
46
+ assert.equal(typeof auth.initialize, "function");
47
+ assert.equal(typeof auth.dispose, "function");
48
+ assert.equal(typeof createMobileCallbackCompleter().completeFromUrl, "function");
49
+ assert.equal(provided.size, 0);
240
50
  });