@phila/sso-vue 0.0.2 → 0.0.3

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/index.js CHANGED
@@ -1,2 +1,133 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("vue"),y=require("pinia"),v=require("@phila/sso-core"),S=Symbol("sso-client"),g=y.defineStore("sso",()=>{const n=r.ref(!1),i=r.ref(!1),o=r.ref(null),t=r.ref(null),u=r.ref(null),l=r.ref(null),f=r.ref(!1);function d(s){n.value=s.isAuthenticated,i.value=s.isLoading,o.value=s.user,t.value=s.token,u.value=s.error,l.value=s.activePolicy,f.value=s.authReady}return{isAuthenticated:n,isLoading:i,user:o,token:t,error:u,activePolicy:l,authReady:f,syncState:d}});function C(n){return{install(i){const o=new v.SSOClient(n.clientConfig);i.provide(S,o),o.events.on("auth:stateChanged",t=>{g().syncState(t)}),n.autoInitialize!==!1&&o.initialize().then(t=>{t&&n.clientConfig.debug&&console.log("[sso-vue] Auto-initialized with response:",t)})}}}function m(){const n=r.inject(S);if(!n)throw new Error("SSOClient not found. Did you install createSSOPlugin?");return n}function E(){const n=g(),i=m(),{isAuthenticated:o,isLoading:t,user:u,token:l,error:f,activePolicy:d,authReady:s}=y.storeToRefs(n),O=r.computed(()=>{const e=u.value?.idTokenClaims;if(!e)return null;const c=e.given_name??e.name??"",a=e.family_name??"";return a?`${c} ${a}`.trim():c});async function P(e){await i.signIn(e)}async function h(e){await i.signInCityEmployee(e)}async function w(e){await i.signOut(e)}async function I(){await i.forgotPassword()}async function _(e){return i.acquireToken(e)}function A(e){const c=u.value?.idTokenClaims;if(!c)return!1;const a=c.roles??c.extension_Roles??[];return Array.isArray(a)&&a.includes(e)}return{isAuthenticated:o,isLoading:t,user:u,token:l,error:f,activePolicy:d,authReady:s,userName:O,signIn:P,signInCityEmployee:h,signOut:w,forgotPassword:I,acquireToken:_,hasRole:A}}function T(n={}){const{signInPolicy:i="B2C_1A_AD_SIGNIN_ONLY",resetPasswordPolicy:o="B2C_1A_PASSWORDRESET",debug:t=!1}=n;return C({clientConfig:{provider:new v.B2CProvider({clientId:void 0,b2cEnvironment:void 0,authorityDomain:void 0,redirectUri:void 0,policies:{signUpSignIn:i,signInOnly:i,resetPassword:o}}),debug:t}})}exports.SSO_CLIENT_KEY=S;exports.createB2CPlugin=T;exports.createSSOPlugin=C;exports.useAuth=E;exports.useSSOClient=m;exports.useSSOStore=g;
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const vue = require("vue");
4
+ const pinia = require("pinia");
5
+ const ssoCore = require("@phila/sso-core");
6
+ const SSO_CLIENT_KEY = /* @__PURE__ */ Symbol("sso-client");
7
+ const useSSOStore = pinia.defineStore("sso", () => {
8
+ const isAuthenticated = vue.ref(false);
9
+ const isLoading = vue.ref(false);
10
+ const user = vue.ref(null);
11
+ const token = vue.ref(null);
12
+ const error = vue.ref(null);
13
+ const activePolicy = vue.ref(null);
14
+ const authReady = vue.ref(false);
15
+ function syncState(state) {
16
+ isAuthenticated.value = state.isAuthenticated;
17
+ isLoading.value = state.isLoading;
18
+ user.value = state.user;
19
+ token.value = state.token;
20
+ error.value = state.error;
21
+ activePolicy.value = state.activePolicy;
22
+ authReady.value = state.authReady;
23
+ }
24
+ return { isAuthenticated, isLoading, user, token, error, activePolicy, authReady, syncState };
25
+ });
26
+ function createSSOPlugin(options) {
27
+ return {
28
+ install(app) {
29
+ const client = new ssoCore.SSOClient(options.clientConfig);
30
+ app.provide(SSO_CLIENT_KEY, client);
31
+ client.events.on("auth:stateChanged", (state) => {
32
+ const store = useSSOStore();
33
+ store.syncState(state);
34
+ });
35
+ if (options.autoInitialize !== false) {
36
+ client.initialize().then((response) => {
37
+ if (response && options.clientConfig.debug) {
38
+ console.log("[sso-vue] Auto-initialized with response:", response);
39
+ }
40
+ });
41
+ }
42
+ }
43
+ };
44
+ }
45
+ function useSSOClient() {
46
+ const client = vue.inject(SSO_CLIENT_KEY);
47
+ if (!client) {
48
+ throw new Error("SSOClient not found. Did you install createSSOPlugin?");
49
+ }
50
+ return client;
51
+ }
52
+ function useAuth() {
53
+ const store = useSSOStore();
54
+ const client = useSSOClient();
55
+ const { isAuthenticated, isLoading, user, token, error, activePolicy, authReady } = pinia.storeToRefs(store);
56
+ const userName = vue.computed(() => {
57
+ const claims = user.value?.idTokenClaims;
58
+ if (!claims) return null;
59
+ const given = claims.given_name ?? claims.name ?? "";
60
+ const family = claims.family_name ?? "";
61
+ return family ? `${given} ${family}`.trim() : given;
62
+ });
63
+ async function signIn(options) {
64
+ await client.signIn(options);
65
+ }
66
+ async function signInCityEmployee(options) {
67
+ await client.signInCityEmployee(options);
68
+ }
69
+ async function signOut(options) {
70
+ await client.signOut(options);
71
+ }
72
+ async function forgotPassword() {
73
+ await client.forgotPassword();
74
+ }
75
+ async function acquireToken(options) {
76
+ return client.acquireToken(options);
77
+ }
78
+ function hasRole(role) {
79
+ const claims = user.value?.idTokenClaims;
80
+ if (!claims) return false;
81
+ const roles = claims.roles ?? claims.extension_Roles ?? [];
82
+ return Array.isArray(roles) && roles.includes(role);
83
+ }
84
+ return {
85
+ // State (readonly refs)
86
+ isAuthenticated,
87
+ isLoading,
88
+ user,
89
+ token,
90
+ error,
91
+ activePolicy,
92
+ authReady,
93
+ userName,
94
+ // Actions
95
+ signIn,
96
+ signInCityEmployee,
97
+ signOut,
98
+ forgotPassword,
99
+ acquireToken,
100
+ // Utilities
101
+ hasRole
102
+ };
103
+ }
104
+ function createB2CPlugin(options = {}) {
105
+ const {
106
+ signInPolicy = "B2C_1A_AD_SIGNIN_ONLY",
107
+ resetPasswordPolicy = "B2C_1A_PASSWORDRESET",
108
+ debug = false
109
+ } = options;
110
+ return createSSOPlugin({
111
+ clientConfig: {
112
+ provider: new ssoCore.B2CProvider({
113
+ clientId: void 0,
114
+ b2cEnvironment: void 0,
115
+ authorityDomain: void 0,
116
+ redirectUri: void 0,
117
+ policies: {
118
+ signUpSignIn: signInPolicy,
119
+ signInOnly: signInPolicy,
120
+ resetPassword: resetPasswordPolicy
121
+ }
122
+ }),
123
+ debug
124
+ }
125
+ });
126
+ }
127
+ exports.SSO_CLIENT_KEY = SSO_CLIENT_KEY;
128
+ exports.createB2CPlugin = createB2CPlugin;
129
+ exports.createSSOPlugin = createSSOPlugin;
130
+ exports.useAuth = useAuth;
131
+ exports.useSSOClient = useSSOClient;
132
+ exports.useSSOStore = useSSOStore;
2
133
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/plugin.ts","../src/composables/useSSOClient.ts","../src/composables/useAuth.ts","../src/createB2CPlugin.ts"],"sourcesContent":["import { ref } from \"vue\";\nimport { defineStore } from \"pinia\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport type { App } from \"vue\";\nimport type { SSOClientConfig, SSOClientState, AuthResponse } from \"@phila/sso-core\";\n\nexport const SSO_CLIENT_KEY = Symbol(\"sso-client\");\n\nexport interface SSOPluginOptions {\n clientConfig: SSOClientConfig;\n autoInitialize?: boolean;\n}\n\nexport const useSSOStore = defineStore(\"sso\", () => {\n const isAuthenticated = ref(false);\n const isLoading = ref(false);\n const user = ref<SSOClientState[\"user\"]>(null);\n const token = ref<string | null>(null);\n const error = ref<Error | null>(null);\n const activePolicy = ref<string | null>(null);\n const authReady = ref(false);\n\n function syncState(state: SSOClientState) {\n isAuthenticated.value = state.isAuthenticated;\n isLoading.value = state.isLoading;\n user.value = state.user;\n token.value = state.token;\n error.value = state.error;\n activePolicy.value = state.activePolicy;\n authReady.value = state.authReady;\n }\n\n return { isAuthenticated, isLoading, user, token, error, activePolicy, authReady, syncState };\n});\n\nexport function createSSOPlugin(options: SSOPluginOptions) {\n return {\n install(app: App) {\n const client = new SSOClient(options.clientConfig);\n\n // Provide the client for useSSOClient()\n app.provide(SSO_CLIENT_KEY, client);\n\n // Subscribe to state changes and sync to Pinia store\n client.events.on(\"auth:stateChanged\", (state: SSOClientState) => {\n const store = useSSOStore();\n store.syncState(state);\n });\n\n // Auto-initialize unless explicitly disabled\n if (options.autoInitialize !== false) {\n client.initialize().then((response: AuthResponse | null) => {\n if (response && options.clientConfig.debug) {\n console.log(\"[sso-vue] Auto-initialized with response:\", response);\n }\n });\n }\n },\n };\n}\n","import { inject } from \"vue\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport { SSO_CLIENT_KEY } from \"../plugin\";\n\n/**\n * Access the raw SSOClient instance.\n * Must be called within a component that is a descendant of createSSOPlugin.\n */\nexport function useSSOClient(): SSOClient {\n const client = inject<SSOClient>(SSO_CLIENT_KEY);\n if (!client) {\n throw new Error(\"SSOClient not found. Did you install createSSOPlugin?\");\n }\n return client;\n}\n","import { computed } from \"vue\";\nimport { storeToRefs } from \"pinia\";\nimport { useSSOStore } from \"../plugin\";\nimport { useSSOClient } from \"./useSSOClient\";\nimport type { SignInOptions, SignOutOptions, TokenOptions } from \"@phila/sso-core\";\n\n/**\n * Primary composable for SSO authentication in Vue 3 apps.\n * API shape is intentionally similar to service-cat's existing useAuth()\n * to minimize migration friction.\n */\nexport function useAuth() {\n const store = useSSOStore();\n const client = useSSOClient();\n const { isAuthenticated, isLoading, user, token, error, activePolicy, authReady } = storeToRefs(store);\n\n // Computed helpers\n const userName = computed(() => {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return null;\n const given = (claims.given_name ?? claims.name ?? \"\") as string;\n const family = (claims.family_name ?? \"\") as string;\n return family ? `${given} ${family}`.trim() : given;\n });\n\n // Actions\n async function signIn(options?: SignInOptions): Promise<void> {\n await client.signIn(options);\n }\n\n async function signInCityEmployee(options?: SignInOptions): Promise<void> {\n await client.signInCityEmployee(options);\n }\n\n async function signOut(options?: SignOutOptions): Promise<void> {\n await client.signOut(options);\n }\n\n async function forgotPassword(): Promise<void> {\n await client.forgotPassword();\n }\n\n async function acquireToken(options?: TokenOptions): Promise<string | null> {\n return client.acquireToken(options);\n }\n\n // Utilities\n function hasRole(role: string): boolean {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return false;\n\n const roles = (claims.roles ?? claims.extension_Roles ?? []) as string[];\n return Array.isArray(roles) && roles.includes(role);\n }\n\n return {\n // State (readonly refs)\n isAuthenticated,\n isLoading,\n user,\n token,\n error,\n activePolicy,\n authReady,\n userName,\n\n // Actions\n signIn,\n signInCityEmployee,\n signOut,\n forgotPassword,\n acquireToken,\n\n // Utilities\n hasRole,\n };\n}\n","// ABOUTME: Convenience factory for vanilla Vue/Vite apps using Azure AD B2C\n// ABOUTME: Reads VITE_SSO_* env vars by convention so apps need zero B2CProvider boilerplate\nimport { B2CProvider } from \"@phila/sso-core\";\nimport { createSSOPlugin } from \"./plugin\";\n\nexport interface B2CPluginOptions {\n signInPolicy?: string;\n resetPasswordPolicy?: string;\n debug?: boolean;\n}\n\n/**\n * Creates a ready-to-use Vue plugin for Azure AD B2C authentication.\n * Reads connection details from VITE_SSO_* environment variables:\n * VITE_SSO_CLIENT_ID, VITE_SSO_TENANT, VITE_SSO_AUTHORITY_DOMAIN, VITE_SSO_REDIRECT_URI\n */\nexport function createB2CPlugin(options: B2CPluginOptions = {}) {\n const {\n signInPolicy = \"B2C_1A_AD_SIGNIN_ONLY\",\n resetPasswordPolicy = \"B2C_1A_PASSWORDRESET\",\n debug = import.meta.env.DEV,\n } = options;\n\n return createSSOPlugin({\n clientConfig: {\n provider: new B2CProvider({\n clientId: import.meta.env.VITE_SSO_CLIENT_ID,\n b2cEnvironment: import.meta.env.VITE_SSO_TENANT,\n authorityDomain: import.meta.env.VITE_SSO_AUTHORITY_DOMAIN,\n redirectUri: import.meta.env.VITE_SSO_REDIRECT_URI,\n policies: {\n signUpSignIn: signInPolicy,\n signInOnly: signInPolicy,\n resetPassword: resetPasswordPolicy,\n },\n }),\n debug,\n },\n });\n}\n"],"names":["SSO_CLIENT_KEY","useSSOStore","defineStore","isAuthenticated","ref","isLoading","user","token","error","activePolicy","authReady","syncState","state","createSSOPlugin","options","app","client","SSOClient","response","useSSOClient","inject","useAuth","store","storeToRefs","userName","computed","claims","given","family","signIn","signInCityEmployee","signOut","forgotPassword","acquireToken","hasRole","role","roles","createB2CPlugin","signInPolicy","resetPasswordPolicy","debug","B2CProvider"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/plugin.ts","../src/composables/useSSOClient.ts","../src/composables/useAuth.ts","../src/createB2CPlugin.ts"],"sourcesContent":["import { ref } from \"vue\";\nimport { defineStore } from \"pinia\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport type { App } from \"vue\";\nimport type { SSOClientConfig, SSOClientState, AuthResponse } from \"@phila/sso-core\";\n\nexport const SSO_CLIENT_KEY = Symbol(\"sso-client\");\n\nexport interface SSOPluginOptions {\n clientConfig: SSOClientConfig;\n autoInitialize?: boolean;\n}\n\nexport const useSSOStore = defineStore(\"sso\", () => {\n const isAuthenticated = ref(false);\n const isLoading = ref(false);\n const user = ref<SSOClientState[\"user\"]>(null);\n const token = ref<string | null>(null);\n const error = ref<Error | null>(null);\n const activePolicy = ref<string | null>(null);\n const authReady = ref(false);\n\n function syncState(state: SSOClientState) {\n isAuthenticated.value = state.isAuthenticated;\n isLoading.value = state.isLoading;\n user.value = state.user;\n token.value = state.token;\n error.value = state.error;\n activePolicy.value = state.activePolicy;\n authReady.value = state.authReady;\n }\n\n return { isAuthenticated, isLoading, user, token, error, activePolicy, authReady, syncState };\n});\n\nexport function createSSOPlugin(options: SSOPluginOptions) {\n return {\n install(app: App) {\n const client = new SSOClient(options.clientConfig);\n\n // Provide the client for useSSOClient()\n app.provide(SSO_CLIENT_KEY, client);\n\n // Subscribe to state changes and sync to Pinia store\n client.events.on(\"auth:stateChanged\", (state: SSOClientState) => {\n const store = useSSOStore();\n store.syncState(state);\n });\n\n // Auto-initialize unless explicitly disabled\n if (options.autoInitialize !== false) {\n client.initialize().then((response: AuthResponse | null) => {\n if (response && options.clientConfig.debug) {\n console.log(\"[sso-vue] Auto-initialized with response:\", response);\n }\n });\n }\n },\n };\n}\n","import { inject } from \"vue\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport { SSO_CLIENT_KEY } from \"../plugin\";\n\n/**\n * Access the raw SSOClient instance.\n * Must be called within a component that is a descendant of createSSOPlugin.\n */\nexport function useSSOClient(): SSOClient {\n const client = inject<SSOClient>(SSO_CLIENT_KEY);\n if (!client) {\n throw new Error(\"SSOClient not found. Did you install createSSOPlugin?\");\n }\n return client;\n}\n","import { computed } from \"vue\";\nimport { storeToRefs } from \"pinia\";\nimport { useSSOStore } from \"../plugin\";\nimport { useSSOClient } from \"./useSSOClient\";\nimport type { SignInOptions, SignOutOptions, TokenOptions } from \"@phila/sso-core\";\n\n/**\n * Primary composable for SSO authentication in Vue 3 apps.\n * API shape is intentionally similar to service-cat's existing useAuth()\n * to minimize migration friction.\n */\nexport function useAuth() {\n const store = useSSOStore();\n const client = useSSOClient();\n const { isAuthenticated, isLoading, user, token, error, activePolicy, authReady } = storeToRefs(store);\n\n // Computed helpers\n const userName = computed(() => {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return null;\n const given = (claims.given_name ?? claims.name ?? \"\") as string;\n const family = (claims.family_name ?? \"\") as string;\n return family ? `${given} ${family}`.trim() : given;\n });\n\n // Actions\n async function signIn(options?: SignInOptions): Promise<void> {\n await client.signIn(options);\n }\n\n async function signInCityEmployee(options?: SignInOptions): Promise<void> {\n await client.signInCityEmployee(options);\n }\n\n async function signOut(options?: SignOutOptions): Promise<void> {\n await client.signOut(options);\n }\n\n async function forgotPassword(): Promise<void> {\n await client.forgotPassword();\n }\n\n async function acquireToken(options?: TokenOptions): Promise<string | null> {\n return client.acquireToken(options);\n }\n\n // Utilities\n function hasRole(role: string): boolean {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return false;\n\n const roles = (claims.roles ?? claims.extension_Roles ?? []) as string[];\n return Array.isArray(roles) && roles.includes(role);\n }\n\n return {\n // State (readonly refs)\n isAuthenticated,\n isLoading,\n user,\n token,\n error,\n activePolicy,\n authReady,\n userName,\n\n // Actions\n signIn,\n signInCityEmployee,\n signOut,\n forgotPassword,\n acquireToken,\n\n // Utilities\n hasRole,\n };\n}\n","// ABOUTME: Convenience factory for vanilla Vue/Vite apps using Azure AD B2C\n// ABOUTME: Reads VITE_SSO_* env vars by convention so apps need zero B2CProvider boilerplate\nimport { B2CProvider } from \"@phila/sso-core\";\nimport { createSSOPlugin } from \"./plugin\";\n\nexport interface B2CPluginOptions {\n signInPolicy?: string;\n resetPasswordPolicy?: string;\n debug?: boolean;\n}\n\n/**\n * Creates a ready-to-use Vue plugin for Azure AD B2C authentication.\n * Reads connection details from VITE_SSO_* environment variables:\n * VITE_SSO_CLIENT_ID, VITE_SSO_TENANT, VITE_SSO_AUTHORITY_DOMAIN, VITE_SSO_REDIRECT_URI\n */\nexport function createB2CPlugin(options: B2CPluginOptions = {}) {\n const {\n signInPolicy = \"B2C_1A_AD_SIGNIN_ONLY\",\n resetPasswordPolicy = \"B2C_1A_PASSWORDRESET\",\n debug = import.meta.env.DEV,\n } = options;\n\n return createSSOPlugin({\n clientConfig: {\n provider: new B2CProvider({\n clientId: import.meta.env.VITE_SSO_CLIENT_ID,\n b2cEnvironment: import.meta.env.VITE_SSO_TENANT,\n authorityDomain: import.meta.env.VITE_SSO_AUTHORITY_DOMAIN,\n redirectUri: import.meta.env.VITE_SSO_REDIRECT_URI,\n policies: {\n signUpSignIn: signInPolicy,\n signInOnly: signInPolicy,\n resetPassword: resetPasswordPolicy,\n },\n }),\n debug,\n },\n });\n}\n"],"names":["defineStore","ref","SSOClient","inject","storeToRefs","computed","B2CProvider"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,108 +1,133 @@
1
- import { ref as c, inject as I, computed as O } from "vue";
2
- import { defineStore as A, storeToRefs as _ } from "pinia";
3
- import { SSOClient as p, B2CProvider as E } from "@phila/sso-core";
4
- const g = /* @__PURE__ */ Symbol("sso-client"), y = A("sso", () => {
5
- const e = c(!1), i = c(!1), o = c(null), t = c(null), r = c(null), l = c(null), f = c(!1);
6
- function d(s) {
7
- e.value = s.isAuthenticated, i.value = s.isLoading, o.value = s.user, t.value = s.token, r.value = s.error, l.value = s.activePolicy, f.value = s.authReady;
1
+ import { ref, inject, computed } from "vue";
2
+ import { defineStore, storeToRefs } from "pinia";
3
+ import { SSOClient, B2CProvider } from "@phila/sso-core";
4
+ const SSO_CLIENT_KEY = /* @__PURE__ */ Symbol("sso-client");
5
+ const useSSOStore = defineStore("sso", () => {
6
+ const isAuthenticated = ref(false);
7
+ const isLoading = ref(false);
8
+ const user = ref(null);
9
+ const token = ref(null);
10
+ const error = ref(null);
11
+ const activePolicy = ref(null);
12
+ const authReady = ref(false);
13
+ function syncState(state) {
14
+ isAuthenticated.value = state.isAuthenticated;
15
+ isLoading.value = state.isLoading;
16
+ user.value = state.user;
17
+ token.value = state.token;
18
+ error.value = state.error;
19
+ activePolicy.value = state.activePolicy;
20
+ authReady.value = state.authReady;
8
21
  }
9
- return { isAuthenticated: e, isLoading: i, user: o, token: t, error: r, activePolicy: l, authReady: f, syncState: d };
22
+ return { isAuthenticated, isLoading, user, token, error, activePolicy, authReady, syncState };
10
23
  });
11
- function R(e) {
24
+ function createSSOPlugin(options) {
12
25
  return {
13
- install(i) {
14
- const o = new p(e.clientConfig);
15
- i.provide(g, o), o.events.on("auth:stateChanged", (t) => {
16
- y().syncState(t);
17
- }), e.autoInitialize !== !1 && o.initialize().then((t) => {
18
- t && e.clientConfig.debug && console.log("[sso-vue] Auto-initialized with response:", t);
26
+ install(app) {
27
+ const client = new SSOClient(options.clientConfig);
28
+ app.provide(SSO_CLIENT_KEY, client);
29
+ client.events.on("auth:stateChanged", (state) => {
30
+ const store = useSSOStore();
31
+ store.syncState(state);
19
32
  });
33
+ if (options.autoInitialize !== false) {
34
+ client.initialize().then((response) => {
35
+ if (response && options.clientConfig.debug) {
36
+ console.log("[sso-vue] Auto-initialized with response:", response);
37
+ }
38
+ });
39
+ }
20
40
  }
21
41
  };
22
42
  }
23
- function k() {
24
- const e = I(g);
25
- if (!e)
43
+ function useSSOClient() {
44
+ const client = inject(SSO_CLIENT_KEY);
45
+ if (!client) {
26
46
  throw new Error("SSOClient not found. Did you install createSSOPlugin?");
27
- return e;
47
+ }
48
+ return client;
28
49
  }
29
- function b() {
30
- const e = y(), i = k(), { isAuthenticated: o, isLoading: t, user: r, token: l, error: f, activePolicy: d, authReady: s } = _(e), S = O(() => {
31
- const n = r.value?.idTokenClaims;
32
- if (!n) return null;
33
- const a = n.given_name ?? n.name ?? "", u = n.family_name ?? "";
34
- return u ? `${a} ${u}`.trim() : a;
50
+ function useAuth() {
51
+ const store = useSSOStore();
52
+ const client = useSSOClient();
53
+ const { isAuthenticated, isLoading, user, token, error, activePolicy, authReady } = storeToRefs(store);
54
+ const userName = computed(() => {
55
+ const claims = user.value?.idTokenClaims;
56
+ if (!claims) return null;
57
+ const given = claims.given_name ?? claims.name ?? "";
58
+ const family = claims.family_name ?? "";
59
+ return family ? `${given} ${family}`.trim() : given;
35
60
  });
36
- async function m(n) {
37
- await i.signIn(n);
61
+ async function signIn(options) {
62
+ await client.signIn(options);
38
63
  }
39
- async function v(n) {
40
- await i.signInCityEmployee(n);
64
+ async function signInCityEmployee(options) {
65
+ await client.signInCityEmployee(options);
41
66
  }
42
- async function C(n) {
43
- await i.signOut(n);
67
+ async function signOut(options) {
68
+ await client.signOut(options);
44
69
  }
45
- async function h() {
46
- await i.forgotPassword();
70
+ async function forgotPassword() {
71
+ await client.forgotPassword();
47
72
  }
48
- async function P(n) {
49
- return i.acquireToken(n);
73
+ async function acquireToken(options) {
74
+ return client.acquireToken(options);
50
75
  }
51
- function w(n) {
52
- const a = r.value?.idTokenClaims;
53
- if (!a) return !1;
54
- const u = a.roles ?? a.extension_Roles ?? [];
55
- return Array.isArray(u) && u.includes(n);
76
+ function hasRole(role) {
77
+ const claims = user.value?.idTokenClaims;
78
+ if (!claims) return false;
79
+ const roles = claims.roles ?? claims.extension_Roles ?? [];
80
+ return Array.isArray(roles) && roles.includes(role);
56
81
  }
57
82
  return {
58
83
  // State (readonly refs)
59
- isAuthenticated: o,
60
- isLoading: t,
61
- user: r,
62
- token: l,
63
- error: f,
64
- activePolicy: d,
65
- authReady: s,
66
- userName: S,
84
+ isAuthenticated,
85
+ isLoading,
86
+ user,
87
+ token,
88
+ error,
89
+ activePolicy,
90
+ authReady,
91
+ userName,
67
92
  // Actions
68
- signIn: m,
69
- signInCityEmployee: v,
70
- signOut: C,
71
- forgotPassword: h,
72
- acquireToken: P,
93
+ signIn,
94
+ signInCityEmployee,
95
+ signOut,
96
+ forgotPassword,
97
+ acquireToken,
73
98
  // Utilities
74
- hasRole: w
99
+ hasRole
75
100
  };
76
101
  }
77
- function B(e = {}) {
102
+ function createB2CPlugin(options = {}) {
78
103
  const {
79
- signInPolicy: i = "B2C_1A_AD_SIGNIN_ONLY",
80
- resetPasswordPolicy: o = "B2C_1A_PASSWORDRESET",
81
- debug: t = !1
82
- } = e;
83
- return R({
104
+ signInPolicy = "B2C_1A_AD_SIGNIN_ONLY",
105
+ resetPasswordPolicy = "B2C_1A_PASSWORDRESET",
106
+ debug = false
107
+ } = options;
108
+ return createSSOPlugin({
84
109
  clientConfig: {
85
- provider: new E({
110
+ provider: new B2CProvider({
86
111
  clientId: void 0,
87
112
  b2cEnvironment: void 0,
88
113
  authorityDomain: void 0,
89
114
  redirectUri: void 0,
90
115
  policies: {
91
- signUpSignIn: i,
92
- signInOnly: i,
93
- resetPassword: o
116
+ signUpSignIn: signInPolicy,
117
+ signInOnly: signInPolicy,
118
+ resetPassword: resetPasswordPolicy
94
119
  }
95
120
  }),
96
- debug: t
121
+ debug
97
122
  }
98
123
  });
99
124
  }
100
125
  export {
101
- g as SSO_CLIENT_KEY,
102
- B as createB2CPlugin,
103
- R as createSSOPlugin,
104
- b as useAuth,
105
- k as useSSOClient,
106
- y as useSSOStore
126
+ SSO_CLIENT_KEY,
127
+ createB2CPlugin,
128
+ createSSOPlugin,
129
+ useAuth,
130
+ useSSOClient,
131
+ useSSOStore
107
132
  };
108
133
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/plugin.ts","../src/composables/useSSOClient.ts","../src/composables/useAuth.ts","../src/createB2CPlugin.ts"],"sourcesContent":["import { ref } from \"vue\";\nimport { defineStore } from \"pinia\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport type { App } from \"vue\";\nimport type { SSOClientConfig, SSOClientState, AuthResponse } from \"@phila/sso-core\";\n\nexport const SSO_CLIENT_KEY = Symbol(\"sso-client\");\n\nexport interface SSOPluginOptions {\n clientConfig: SSOClientConfig;\n autoInitialize?: boolean;\n}\n\nexport const useSSOStore = defineStore(\"sso\", () => {\n const isAuthenticated = ref(false);\n const isLoading = ref(false);\n const user = ref<SSOClientState[\"user\"]>(null);\n const token = ref<string | null>(null);\n const error = ref<Error | null>(null);\n const activePolicy = ref<string | null>(null);\n const authReady = ref(false);\n\n function syncState(state: SSOClientState) {\n isAuthenticated.value = state.isAuthenticated;\n isLoading.value = state.isLoading;\n user.value = state.user;\n token.value = state.token;\n error.value = state.error;\n activePolicy.value = state.activePolicy;\n authReady.value = state.authReady;\n }\n\n return { isAuthenticated, isLoading, user, token, error, activePolicy, authReady, syncState };\n});\n\nexport function createSSOPlugin(options: SSOPluginOptions) {\n return {\n install(app: App) {\n const client = new SSOClient(options.clientConfig);\n\n // Provide the client for useSSOClient()\n app.provide(SSO_CLIENT_KEY, client);\n\n // Subscribe to state changes and sync to Pinia store\n client.events.on(\"auth:stateChanged\", (state: SSOClientState) => {\n const store = useSSOStore();\n store.syncState(state);\n });\n\n // Auto-initialize unless explicitly disabled\n if (options.autoInitialize !== false) {\n client.initialize().then((response: AuthResponse | null) => {\n if (response && options.clientConfig.debug) {\n console.log(\"[sso-vue] Auto-initialized with response:\", response);\n }\n });\n }\n },\n };\n}\n","import { inject } from \"vue\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport { SSO_CLIENT_KEY } from \"../plugin\";\n\n/**\n * Access the raw SSOClient instance.\n * Must be called within a component that is a descendant of createSSOPlugin.\n */\nexport function useSSOClient(): SSOClient {\n const client = inject<SSOClient>(SSO_CLIENT_KEY);\n if (!client) {\n throw new Error(\"SSOClient not found. Did you install createSSOPlugin?\");\n }\n return client;\n}\n","import { computed } from \"vue\";\nimport { storeToRefs } from \"pinia\";\nimport { useSSOStore } from \"../plugin\";\nimport { useSSOClient } from \"./useSSOClient\";\nimport type { SignInOptions, SignOutOptions, TokenOptions } from \"@phila/sso-core\";\n\n/**\n * Primary composable for SSO authentication in Vue 3 apps.\n * API shape is intentionally similar to service-cat's existing useAuth()\n * to minimize migration friction.\n */\nexport function useAuth() {\n const store = useSSOStore();\n const client = useSSOClient();\n const { isAuthenticated, isLoading, user, token, error, activePolicy, authReady } = storeToRefs(store);\n\n // Computed helpers\n const userName = computed(() => {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return null;\n const given = (claims.given_name ?? claims.name ?? \"\") as string;\n const family = (claims.family_name ?? \"\") as string;\n return family ? `${given} ${family}`.trim() : given;\n });\n\n // Actions\n async function signIn(options?: SignInOptions): Promise<void> {\n await client.signIn(options);\n }\n\n async function signInCityEmployee(options?: SignInOptions): Promise<void> {\n await client.signInCityEmployee(options);\n }\n\n async function signOut(options?: SignOutOptions): Promise<void> {\n await client.signOut(options);\n }\n\n async function forgotPassword(): Promise<void> {\n await client.forgotPassword();\n }\n\n async function acquireToken(options?: TokenOptions): Promise<string | null> {\n return client.acquireToken(options);\n }\n\n // Utilities\n function hasRole(role: string): boolean {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return false;\n\n const roles = (claims.roles ?? claims.extension_Roles ?? []) as string[];\n return Array.isArray(roles) && roles.includes(role);\n }\n\n return {\n // State (readonly refs)\n isAuthenticated,\n isLoading,\n user,\n token,\n error,\n activePolicy,\n authReady,\n userName,\n\n // Actions\n signIn,\n signInCityEmployee,\n signOut,\n forgotPassword,\n acquireToken,\n\n // Utilities\n hasRole,\n };\n}\n","// ABOUTME: Convenience factory for vanilla Vue/Vite apps using Azure AD B2C\n// ABOUTME: Reads VITE_SSO_* env vars by convention so apps need zero B2CProvider boilerplate\nimport { B2CProvider } from \"@phila/sso-core\";\nimport { createSSOPlugin } from \"./plugin\";\n\nexport interface B2CPluginOptions {\n signInPolicy?: string;\n resetPasswordPolicy?: string;\n debug?: boolean;\n}\n\n/**\n * Creates a ready-to-use Vue plugin for Azure AD B2C authentication.\n * Reads connection details from VITE_SSO_* environment variables:\n * VITE_SSO_CLIENT_ID, VITE_SSO_TENANT, VITE_SSO_AUTHORITY_DOMAIN, VITE_SSO_REDIRECT_URI\n */\nexport function createB2CPlugin(options: B2CPluginOptions = {}) {\n const {\n signInPolicy = \"B2C_1A_AD_SIGNIN_ONLY\",\n resetPasswordPolicy = \"B2C_1A_PASSWORDRESET\",\n debug = import.meta.env.DEV,\n } = options;\n\n return createSSOPlugin({\n clientConfig: {\n provider: new B2CProvider({\n clientId: import.meta.env.VITE_SSO_CLIENT_ID,\n b2cEnvironment: import.meta.env.VITE_SSO_TENANT,\n authorityDomain: import.meta.env.VITE_SSO_AUTHORITY_DOMAIN,\n redirectUri: import.meta.env.VITE_SSO_REDIRECT_URI,\n policies: {\n signUpSignIn: signInPolicy,\n signInOnly: signInPolicy,\n resetPassword: resetPasswordPolicy,\n },\n }),\n debug,\n },\n });\n}\n"],"names":["SSO_CLIENT_KEY","useSSOStore","defineStore","isAuthenticated","ref","isLoading","user","token","error","activePolicy","authReady","syncState","state","createSSOPlugin","options","app","client","SSOClient","response","useSSOClient","inject","useAuth","store","storeToRefs","userName","computed","claims","given","family","signIn","signInCityEmployee","signOut","forgotPassword","acquireToken","hasRole","role","roles","createB2CPlugin","signInPolicy","resetPasswordPolicy","debug","B2CProvider"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/plugin.ts","../src/composables/useSSOClient.ts","../src/composables/useAuth.ts","../src/createB2CPlugin.ts"],"sourcesContent":["import { ref } from \"vue\";\nimport { defineStore } from \"pinia\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport type { App } from \"vue\";\nimport type { SSOClientConfig, SSOClientState, AuthResponse } from \"@phila/sso-core\";\n\nexport const SSO_CLIENT_KEY = Symbol(\"sso-client\");\n\nexport interface SSOPluginOptions {\n clientConfig: SSOClientConfig;\n autoInitialize?: boolean;\n}\n\nexport const useSSOStore = defineStore(\"sso\", () => {\n const isAuthenticated = ref(false);\n const isLoading = ref(false);\n const user = ref<SSOClientState[\"user\"]>(null);\n const token = ref<string | null>(null);\n const error = ref<Error | null>(null);\n const activePolicy = ref<string | null>(null);\n const authReady = ref(false);\n\n function syncState(state: SSOClientState) {\n isAuthenticated.value = state.isAuthenticated;\n isLoading.value = state.isLoading;\n user.value = state.user;\n token.value = state.token;\n error.value = state.error;\n activePolicy.value = state.activePolicy;\n authReady.value = state.authReady;\n }\n\n return { isAuthenticated, isLoading, user, token, error, activePolicy, authReady, syncState };\n});\n\nexport function createSSOPlugin(options: SSOPluginOptions) {\n return {\n install(app: App) {\n const client = new SSOClient(options.clientConfig);\n\n // Provide the client for useSSOClient()\n app.provide(SSO_CLIENT_KEY, client);\n\n // Subscribe to state changes and sync to Pinia store\n client.events.on(\"auth:stateChanged\", (state: SSOClientState) => {\n const store = useSSOStore();\n store.syncState(state);\n });\n\n // Auto-initialize unless explicitly disabled\n if (options.autoInitialize !== false) {\n client.initialize().then((response: AuthResponse | null) => {\n if (response && options.clientConfig.debug) {\n console.log(\"[sso-vue] Auto-initialized with response:\", response);\n }\n });\n }\n },\n };\n}\n","import { inject } from \"vue\";\nimport { SSOClient } from \"@phila/sso-core\";\nimport { SSO_CLIENT_KEY } from \"../plugin\";\n\n/**\n * Access the raw SSOClient instance.\n * Must be called within a component that is a descendant of createSSOPlugin.\n */\nexport function useSSOClient(): SSOClient {\n const client = inject<SSOClient>(SSO_CLIENT_KEY);\n if (!client) {\n throw new Error(\"SSOClient not found. Did you install createSSOPlugin?\");\n }\n return client;\n}\n","import { computed } from \"vue\";\nimport { storeToRefs } from \"pinia\";\nimport { useSSOStore } from \"../plugin\";\nimport { useSSOClient } from \"./useSSOClient\";\nimport type { SignInOptions, SignOutOptions, TokenOptions } from \"@phila/sso-core\";\n\n/**\n * Primary composable for SSO authentication in Vue 3 apps.\n * API shape is intentionally similar to service-cat's existing useAuth()\n * to minimize migration friction.\n */\nexport function useAuth() {\n const store = useSSOStore();\n const client = useSSOClient();\n const { isAuthenticated, isLoading, user, token, error, activePolicy, authReady } = storeToRefs(store);\n\n // Computed helpers\n const userName = computed(() => {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return null;\n const given = (claims.given_name ?? claims.name ?? \"\") as string;\n const family = (claims.family_name ?? \"\") as string;\n return family ? `${given} ${family}`.trim() : given;\n });\n\n // Actions\n async function signIn(options?: SignInOptions): Promise<void> {\n await client.signIn(options);\n }\n\n async function signInCityEmployee(options?: SignInOptions): Promise<void> {\n await client.signInCityEmployee(options);\n }\n\n async function signOut(options?: SignOutOptions): Promise<void> {\n await client.signOut(options);\n }\n\n async function forgotPassword(): Promise<void> {\n await client.forgotPassword();\n }\n\n async function acquireToken(options?: TokenOptions): Promise<string | null> {\n return client.acquireToken(options);\n }\n\n // Utilities\n function hasRole(role: string): boolean {\n const claims = user.value?.idTokenClaims as Record<string, unknown> | undefined;\n if (!claims) return false;\n\n const roles = (claims.roles ?? claims.extension_Roles ?? []) as string[];\n return Array.isArray(roles) && roles.includes(role);\n }\n\n return {\n // State (readonly refs)\n isAuthenticated,\n isLoading,\n user,\n token,\n error,\n activePolicy,\n authReady,\n userName,\n\n // Actions\n signIn,\n signInCityEmployee,\n signOut,\n forgotPassword,\n acquireToken,\n\n // Utilities\n hasRole,\n };\n}\n","// ABOUTME: Convenience factory for vanilla Vue/Vite apps using Azure AD B2C\n// ABOUTME: Reads VITE_SSO_* env vars by convention so apps need zero B2CProvider boilerplate\nimport { B2CProvider } from \"@phila/sso-core\";\nimport { createSSOPlugin } from \"./plugin\";\n\nexport interface B2CPluginOptions {\n signInPolicy?: string;\n resetPasswordPolicy?: string;\n debug?: boolean;\n}\n\n/**\n * Creates a ready-to-use Vue plugin for Azure AD B2C authentication.\n * Reads connection details from VITE_SSO_* environment variables:\n * VITE_SSO_CLIENT_ID, VITE_SSO_TENANT, VITE_SSO_AUTHORITY_DOMAIN, VITE_SSO_REDIRECT_URI\n */\nexport function createB2CPlugin(options: B2CPluginOptions = {}) {\n const {\n signInPolicy = \"B2C_1A_AD_SIGNIN_ONLY\",\n resetPasswordPolicy = \"B2C_1A_PASSWORDRESET\",\n debug = import.meta.env.DEV,\n } = options;\n\n return createSSOPlugin({\n clientConfig: {\n provider: new B2CProvider({\n clientId: import.meta.env.VITE_SSO_CLIENT_ID,\n b2cEnvironment: import.meta.env.VITE_SSO_TENANT,\n authorityDomain: import.meta.env.VITE_SSO_AUTHORITY_DOMAIN,\n redirectUri: import.meta.env.VITE_SSO_REDIRECT_URI,\n policies: {\n signUpSignIn: signInPolicy,\n signInOnly: signInPolicy,\n resetPassword: resetPasswordPolicy,\n },\n }),\n debug,\n },\n });\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phila/sso-vue",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "description": "Vue 3 adapter for @phila/sso-core",
6
6
  "main": "./dist/index.js",
@@ -26,7 +26,7 @@
26
26
  "author": "City of Philadelphia",
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
- "@phila/sso-core": "0.0.2"
29
+ "@phila/sso-core": "0.0.3"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "vue": "^3.0.0",