@skill3/sdk-angular 0.0.0-stage → 0.1.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.
package/README.md CHANGED
@@ -1,3 +1,103 @@
1
- # Temporary Holding Version
1
+ # @skill3/sdk-angular
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Angular client ของ Skill3 API (**ตัวต่อจาก `@digione/ngx-core`**): ยืนยัน site จากโดเมน (`X-Client-Site`), เข้าสู่ระบบผู้ใช้พร้อมต่ออายุ token อัตโนมัติ, และเรียก REST endpoint ใดก็ได้
4
+ logic อยู่ใน `@skill3/sdk-core` แพ็กเกจนี้เพิ่ม `provideSkill3()`, service ที่ `inject()` ได้ พร้อม signal / observable และส่ง request ผ่าน `HttpClient` ของแอป
5
+
6
+ ย้ายจาก ngx-core ดู `docs/migration/ngx-core-to-sdk-angular.md` ใน repo (storage key เดิม ผู้ใช้ไม่หลุด login)
7
+
8
+ ## ติดตั้ง
9
+
10
+ ```bash
11
+ npm install @skill3/sdk-angular # ติดตั้ง @skill3/sdk-core ให้ด้วย
12
+ ```
13
+
14
+ peer dependency: `@angular/core`, `@angular/common` 22, `rxjs` ^7.4
15
+
16
+ ## ตั้งค่า
17
+
18
+ ```ts
19
+ // app.config.ts
20
+ import { provideHttpClient, withFetch } from '@angular/common/http';
21
+ import { provideLocalStorage, provideSkill3 } from '@skill3/sdk-angular';
22
+ import { environment } from '../environments/environment';
23
+
24
+ export const appConfig: ApplicationConfig = {
25
+ providers: [
26
+ provideHttpClient(withFetch()), // แนะนำ (SSR); request ของ SDK วิ่งผ่าน HttpClient + interceptor ของแอป
27
+ provideSkill3({
28
+ scope: 'site', // 'site' | 'organ' | 'core' (ค่าเริ่มต้น 'organ')
29
+ environment, // apiUrl, apiUrls, apiUrlSystem, customApiUrl, defaultDomain, production, isMobile, authDomainOption
30
+ storage: provideLocalStorage(), // ค่าเริ่มต้นคือเก็บใน memory (หายเมื่อ reload)
31
+ }),
32
+ ],
33
+ };
34
+ ```
35
+
36
+ option เหมือน `provideDigione` ของ ngx-core ทุกตัว (ตารางเต็มใน README ของ core) และเพิ่ม:
37
+
38
+ | option | ความหมาย |
39
+ |---|---|
40
+ | `isServer` | ค่าเริ่มต้นตรวจจาก `PLATFORM_ID` |
41
+ | `useHttpClient` | ค่าเริ่มต้น `true`: ส่งผ่าน `HttpClient` (interceptor, XSRF, SSR transfer cache) · `false` → `fetch` ตรง |
42
+ | `fetch`, `hostname` | เหมือน core (`hostname` ค่าเริ่มต้นจาก `DOCUMENT`) |
43
+
44
+ ### config ที่ต้อง inject ค่าอื่น (เช่น SSR)
45
+
46
+ ```ts
47
+ provideSkill3(
48
+ () => ({ scope: 'site', environment, tokenRef: inject(REQUEST_TOKEN_REF), site: inject(REQUEST_SITE) }),
49
+ provideLocalStorage(), // storage ใส่เป็น argument ที่ 2 เมื่อใช้ factory
50
+ );
51
+ ```
52
+
53
+ ### SSR
54
+
55
+ - ทุก request ลงทะเบียน `PendingTasks` → SSR (zoneless) รอข้อมูลก่อน render
56
+ - request ส่ง credentials เสมอ transfer cache ของ Angular จึงข้ามเป็นค่าเริ่มต้น (browser ยิงซ้ำหลัง hydrate) ถ้าไม่อยากยิงซ้ำ:
57
+
58
+ ```ts
59
+ provideClientHydration(withHttpTransferCacheOptions({ includeRequestsWithCredentials: true }))
60
+ ```
61
+
62
+ ### Ionic Storage
63
+
64
+ ```ts
65
+ import { Storage } from '@ionic/storage-angular';
66
+
67
+ provideSkill3({ scope: 'site', environment, storage: provideCustomStorage(() => inject(Storage)) }),
68
+ provideAppInitializer(() => inject(Storage).create()), // ต้อง create ก่อนมี request แรก
69
+ ```
70
+
71
+ ## ใช้งาน
72
+
73
+ ```ts
74
+ const site = inject(CoreSiteService);
75
+ const auth = inject(AuthService);
76
+ const custom = inject(CustomService);
77
+
78
+ await site.authDomain(location.hostname, { include: { setting: true } });
79
+
80
+ const { data, total } = await custom.fetch.get('sites/web_languages', { query: { lang_code: 'th' } });
81
+ const res = await custom.fetch.post('site/carts', { data: { product_id: 15, qty: 1 } }); // Skill3Response
82
+
83
+ await auth.signInWithEmail(email, password);
84
+ auth.user(); // signal
85
+ auth.user$; // observable (ส่งค่าปัจจุบันตอน subscribe)
86
+ site.siteReady(); // signal
87
+ site.onSiteTokenRenew().subscribe(() => {}); // ทุกครั้งที่ต่ออายุ site token อัตโนมัติเสร็จ
88
+ await auth.signOut();
89
+ ```
90
+
91
+ | เรียก | ได้ |
92
+ |---|---|
93
+ | `fetch.get` (ไม่ใส่ `single`) | `{ data, total: number \| null, headers }` (204 → `{ data: [], total: null, headers }`) |
94
+ | `fetch.get(..., { single: true })`, `profile().object()` | body (204 → `null`) |
95
+ | `fetch.post/put/delete`, `profile().create/update/delete/stream`, `signUpWithEmail`, `deleteAccount` | `Skill3Response` (`status`, `headers`, `body`, `url`) |
96
+
97
+ error เป็น `Skill3HttpError` (`status`, `error` = body, `headers`) · `errorCode(err)` อ่าน code ของ API เหมือนเดิม
98
+
99
+ interceptor ของแอปที่อ่าน **response body** ของ request จาก SDK จะเห็นเป็น `ArrayBuffer` (SDK parse เอง) interceptor ที่แก้ request / header / จับ error ไม่กระทบ
100
+
101
+ ## พัฒนา SDK
102
+
103
+ ดู `CLAUDE.md` และ `docs/ARCHITECTURE.md` ใน repo
package/dist/index.cjs ADDED
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ AuthService: () => AuthService,
25
+ CoreSiteService: () => CoreSiteService,
26
+ SKILL3_CLIENT: () => SKILL3_CLIENT,
27
+ SKILL3_CONFIG: () => SKILL3_CONFIG,
28
+ StorageProvider: () => StorageProvider,
29
+ httpClientFetch: () => httpClientFetch,
30
+ provideCustomStorage: () => provideCustomStorage,
31
+ provideLocalStorage: () => provideLocalStorage,
32
+ provideSkill3: () => provideSkill3,
33
+ valueToObservable: () => valueToObservable,
34
+ valueToSignal: () => valueToSignal
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ __reExport(index_exports, require("@skill3/sdk-core"), module.exports);
38
+
39
+ // src/provide.ts
40
+ var import_core3 = require("@angular/core");
41
+ var import_common2 = require("@angular/common");
42
+ var import_http2 = require("@angular/common/http");
43
+ var import_sdk_core4 = require("@skill3/sdk-core");
44
+
45
+ // src/http-client-fetch.ts
46
+ var import_http = require("@angular/common/http");
47
+ function httpClientFetch(http) {
48
+ return (input, init = {}) => new Promise((resolve, reject) => {
49
+ const signal2 = init.signal;
50
+ if (signal2?.aborted) return reject(signal2.reason);
51
+ let headers = new import_http.HttpHeaders();
52
+ new Headers(init.headers).forEach((value, key) => headers = headers.set(key, value));
53
+ let subscription;
54
+ const onAbort = () => {
55
+ subscription?.unsubscribe();
56
+ reject(signal2?.reason);
57
+ };
58
+ const done = () => signal2?.removeEventListener("abort", onAbort);
59
+ signal2?.addEventListener("abort", onAbort, { once: true });
60
+ subscription = http.request(init.method ?? "GET", input instanceof Request ? input.url : String(input), {
61
+ body: init.body ?? null,
62
+ headers,
63
+ withCredentials: init.credentials === "include",
64
+ observe: "response",
65
+ // not 'blob': the SSR transfer cache stores blob bodies as an empty string
66
+ responseType: "arraybuffer",
67
+ // keep the list total when the app enables the transfer cache
68
+ transferCache: { includeHeaders: ["x-total-count"] }
69
+ }).subscribe({
70
+ next: (res) => {
71
+ done();
72
+ toResponse(res.status, res.statusText, res.headers, res.body).then(resolve, reject);
73
+ },
74
+ error: (err) => {
75
+ done();
76
+ if (err instanceof import_http.HttpErrorResponse && err.status >= 200) {
77
+ toResponse(err.status, err.statusText, err.headers, err.error).then(resolve, reject);
78
+ } else {
79
+ reject(new TypeError("Failed to fetch", { cause: err }));
80
+ }
81
+ }
82
+ });
83
+ });
84
+ }
85
+ async function toResponse(status, statusText, httpHeaders, body) {
86
+ const headers = new Headers();
87
+ for (const key of httpHeaders.keys()) {
88
+ for (const value of httpHeaders.getAll(key) ?? []) headers.append(key, value);
89
+ }
90
+ const noBody = status === 204 || status === 205 || status === 304;
91
+ return new Response(noBody ? null : await toBodyInit(body), { status, statusText, headers });
92
+ }
93
+ async function toBodyInit(body) {
94
+ if (body === null || body === void 0) return null;
95
+ if (typeof body === "string" || body instanceof ArrayBuffer) return body;
96
+ if (typeof body.arrayBuffer === "function") return body.arrayBuffer();
97
+ return JSON.stringify(body);
98
+ }
99
+
100
+ // src/pending-tasks-http.ts
101
+ var import_sdk_core = require("@skill3/sdk-core");
102
+ var PendingTasksHttp = class extends import_sdk_core.Skill3Http {
103
+ constructor(config, store, state, tasks) {
104
+ super(config, store, state);
105
+ this.tasks = tasks;
106
+ }
107
+ tasks;
108
+ request(method, target, option) {
109
+ const done = this.tasks.add();
110
+ return super.request(method, target, option).finally(done);
111
+ }
112
+ };
113
+
114
+ // src/services.ts
115
+ var import_rxjs2 = require("rxjs");
116
+ var import_sdk_core2 = require("@skill3/sdk-core");
117
+
118
+ // src/interop.ts
119
+ var import_core = require("@angular/core");
120
+ var import_rxjs = require("rxjs");
121
+ function valueToSignal(value, destroyRef) {
122
+ const result = (0, import_core.signal)(value.get());
123
+ destroyRef.onDestroy(value.subscribe((next) => result.set(next)));
124
+ return result.asReadonly();
125
+ }
126
+ function valueToObservable(value) {
127
+ return new import_rxjs.Observable((subscriber) => {
128
+ subscriber.next(value.get());
129
+ return value.subscribe((next) => subscriber.next(next));
130
+ });
131
+ }
132
+
133
+ // src/services.ts
134
+ var AuthService = class extends import_sdk_core2.AuthService {
135
+ /** Signed-in user as a signal (`null` when signed out). */
136
+ user;
137
+ /** Signed-in user as an observable (`null` when signed out). Emits the current user on subscribe. */
138
+ user$;
139
+ constructor(client, destroyRef) {
140
+ super(client.config, client.http, client.store, client.state);
141
+ this.user = valueToSignal(client.state.user, destroyRef);
142
+ this.user$ = valueToObservable(client.state.user);
143
+ }
144
+ /** Emits the stored user (when `dispatch`) and returns `user$`. */
145
+ async subscribeUser({
146
+ prefix_key,
147
+ dispatch = true
148
+ } = {}) {
149
+ const user = await this.getUser({ prefix_key });
150
+ if (dispatch) this.state.setUser(user);
151
+ return this.user$;
152
+ }
153
+ };
154
+ var CoreSiteService = class extends import_sdk_core2.CoreSiteService {
155
+ /** true once a site token is known. */
156
+ siteReady;
157
+ constructor(client, auth, destroyRef) {
158
+ super(client.config, client.http, client.store, client.state, auth);
159
+ this.siteReady = valueToSignal(client.state.siteReady, destroyRef);
160
+ }
161
+ /** Emits `true` now and every time an automatic site-token renewal finishes. */
162
+ onSiteTokenRenew() {
163
+ return new import_rxjs2.Observable(
164
+ (subscriber) => this.state.onSiteRenewed((renewed) => subscriber.next(renewed))
165
+ );
166
+ }
167
+ };
168
+
169
+ // src/storage.ts
170
+ var import_core2 = require("@angular/core");
171
+ var import_common = require("@angular/common");
172
+ var import_sdk_core3 = require("@skill3/sdk-core");
173
+ var StorageProvider = class {
174
+ };
175
+ function provideLocalStorage() {
176
+ return {
177
+ provide: StorageProvider,
178
+ useFactory: () => new import_sdk_core3.LocalStorageProvider((0, import_common.isPlatformBrowser)((0, import_core2.inject)(import_core2.PLATFORM_ID)) ? void 0 : null)
179
+ };
180
+ }
181
+ function provideCustomStorage(factory) {
182
+ return { provide: StorageProvider, useFactory: () => new import_sdk_core3.CustomStorageProvider(factory()) };
183
+ }
184
+
185
+ // src/provide.ts
186
+ var SKILL3_CLIENT = new import_core3.InjectionToken("SKILL3_CLIENT");
187
+ var SKILL3_CONFIG = new import_core3.InjectionToken("SKILL3_CONFIG");
188
+ function provideSkill3(config = {}, storageProvider) {
189
+ const storage = storageProvider ?? (typeof config === "function" ? void 0 : config.storage);
190
+ const client = () => (0, import_core3.inject)(SKILL3_CLIENT);
191
+ return (0, import_core3.makeEnvironmentProviders)([
192
+ {
193
+ provide: SKILL3_CLIENT,
194
+ useFactory: () => createClient(typeof config === "function" ? config() : config)
195
+ },
196
+ storage ?? { provide: StorageProvider, useClass: import_sdk_core4.MemoryStorageProvider },
197
+ { provide: SKILL3_CONFIG, useFactory: () => client().config },
198
+ { provide: import_sdk_core4.Skill3State, useFactory: () => client().state },
199
+ { provide: import_sdk_core4.SessionStore, useFactory: () => client().store },
200
+ { provide: import_sdk_core4.Skill3Http, useFactory: () => client().http },
201
+ { provide: AuthService, useFactory: () => new AuthService(client(), (0, import_core3.inject)(import_core3.DestroyRef)) },
202
+ {
203
+ provide: CoreSiteService,
204
+ useFactory: () => new CoreSiteService(client(), (0, import_core3.inject)(AuthService), (0, import_core3.inject)(import_core3.DestroyRef))
205
+ },
206
+ { provide: import_sdk_core4.CustomService, useFactory: () => new import_sdk_core4.CustomService(client().http) }
207
+ ]);
208
+ }
209
+ function createClient({
210
+ storage: _storage,
211
+ useHttpClient = true,
212
+ ...config
213
+ }) {
214
+ const fetch = config.fetch ?? (useHttpClient ? httpClientFetch((0, import_core3.inject)(import_http2.HttpClient)) : void 0);
215
+ const document = (0, import_core3.inject)(import_core3.DOCUMENT, { optional: true });
216
+ const tasks = (0, import_core3.inject)(import_core3.PendingTasks);
217
+ return (0, import_sdk_core4.createSkill3)(
218
+ {
219
+ ...config,
220
+ storage: (0, import_core3.inject)(StorageProvider),
221
+ isServer: config.isServer ?? (0, import_common2.isPlatformServer)((0, import_core3.inject)(import_core3.PLATFORM_ID)),
222
+ fetch,
223
+ hostname: config.hostname ?? (() => document?.location?.hostname)
224
+ },
225
+ { createHttp: (...args) => new PendingTasksHttp(...args, tasks) }
226
+ );
227
+ }
228
+ // Annotate the CommonJS export names for ESM import in node:
229
+ 0 && (module.exports = {
230
+ AuthService,
231
+ CoreSiteService,
232
+ SKILL3_CLIENT,
233
+ SKILL3_CONFIG,
234
+ StorageProvider,
235
+ httpClientFetch,
236
+ provideCustomStorage,
237
+ provideLocalStorage,
238
+ provideSkill3,
239
+ valueToObservable,
240
+ valueToSignal,
241
+ ...require("@skill3/sdk-core")
242
+ });
243
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/provide.ts","../src/http-client-fetch.ts","../src/pending-tasks-http.ts","../src/services.ts","../src/interop.ts","../src/storage.ts"],"sourcesContent":["/*\n * Public API Surface of @skill3/sdk-angular\n */\n\n// everything of the core; the local exports below replace the core ones with the same name\nexport * from '@skill3/sdk-core';\n\nexport { provideSkill3, SKILL3_CLIENT, SKILL3_CONFIG } from './provide';\nexport type { Skill3AngularConfig } from './provide';\nexport { AuthService, CoreSiteService } from './services';\nexport { StorageProvider, provideLocalStorage, provideCustomStorage } from './storage';\nexport { httpClientFetch } from './http-client-fetch';\nexport { valueToObservable, valueToSignal } from './interop';\n","import {\n DOCUMENT,\n DestroyRef,\n EnvironmentProviders,\n InjectionToken,\n PLATFORM_ID,\n PendingTasks,\n Provider,\n inject,\n makeEnvironmentProviders,\n} from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport { HttpClient } from '@angular/common/http';\nimport {\n CustomService,\n MemoryStorageProvider,\n SessionStore,\n Skill3Http,\n Skill3State,\n createSkill3,\n type ResolvedSkill3Config,\n type Skill3Client,\n type Skill3Config,\n} from '@skill3/sdk-core';\nimport { httpClientFetch } from './http-client-fetch';\nimport { PendingTasksHttp } from './pending-tasks-http';\nimport { AuthService, CoreSiteService } from './services';\nimport { StorageProvider } from './storage';\n\nexport interface Skill3AngularConfig extends Omit<Skill3Config, 'storage'> {\n /** Storage provider, e.g. `provideLocalStorage()`. Default: in-memory (lost on reload). */\n storage?: Provider;\n /**\n * Default true: send requests through `HttpClient` (interceptors and `withFetch()` of\n * `provideHttpClient()`, SSR transfer cache). false → plain `fetch`. Ignored when `fetch` is set.\n */\n useHttpClient?: boolean;\n}\n\n/** The `Skill3Client` behind the injectable services. */\nexport const SKILL3_CLIENT = new InjectionToken<Skill3Client>('SKILL3_CLIENT');\n\n/** Config after defaults are applied. */\nexport const SKILL3_CONFIG = new InjectionToken<ResolvedSkill3Config>('SKILL3_CONFIG');\n\n/**\n * Registers the library.\n *\n * ```ts\n * bootstrapApplication(App, {\n * providers: [\n * provideHttpClient(withFetch()),\n * provideSkill3({ scope: 'site', environment, storage: provideLocalStorage() }),\n * ],\n * });\n * ```\n *\n * Pass a factory instead of an object when the config depends on other providers\n * (e.g. SSR request data). The factory runs in an injection context, so it cannot\n * return `storage`: pass the storage provider as the second argument instead.\n */\nexport function provideSkill3(\n config: Skill3AngularConfig | (() => Skill3AngularConfig) = {},\n storageProvider?: Provider,\n): EnvironmentProviders {\n const storage = storageProvider ?? (typeof config === 'function' ? undefined : config.storage);\n const client = () => inject(SKILL3_CLIENT);\n return makeEnvironmentProviders([\n {\n provide: SKILL3_CLIENT,\n useFactory: () => createClient(typeof config === 'function' ? config() : config),\n },\n storage ?? { provide: StorageProvider, useClass: MemoryStorageProvider },\n { provide: SKILL3_CONFIG, useFactory: () => client().config },\n { provide: Skill3State, useFactory: () => client().state },\n { provide: SessionStore, useFactory: () => client().store },\n { provide: Skill3Http, useFactory: () => client().http },\n { provide: AuthService, useFactory: () => new AuthService(client(), inject(DestroyRef)) },\n {\n provide: CoreSiteService,\n useFactory: () => new CoreSiteService(client(), inject(AuthService), inject(DestroyRef)),\n },\n { provide: CustomService, useFactory: () => new CustomService(client().http) },\n ]);\n}\n\nfunction createClient({\n storage: _storage,\n useHttpClient = true,\n ...config\n}: Skill3AngularConfig): Skill3Client {\n // HttpClient is provided in root (Angular 22), provideHttpClient() only configures it\n const fetch = config.fetch ?? (useHttpClient ? httpClientFetch(inject(HttpClient)) : undefined);\n const document = inject(DOCUMENT, { optional: true });\n const tasks = inject(PendingTasks);\n return createSkill3(\n {\n ...config,\n storage: inject(StorageProvider),\n isServer: config.isServer ?? isPlatformServer(inject(PLATFORM_ID)),\n fetch,\n hostname: config.hostname ?? (() => document?.location?.hostname),\n },\n { createHttp: (...args) => new PendingTasksHttp(...args, tasks) },\n );\n}\n","import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';\nimport type { Subscription } from 'rxjs';\n\n/**\n * `fetch` that sends through Angular's `HttpClient`, so the app's interceptors, XSRF handling\n * and the SSR transfer cache still apply. Non-2xx answers resolve as a `Response` (like `fetch`);\n * only network failures reject.\n */\nexport function httpClientFetch(http: HttpClient): typeof fetch {\n return (input, init = {}) =>\n new Promise<Response>((resolve, reject) => {\n const signal = init.signal;\n if (signal?.aborted) return reject(signal.reason);\n\n let headers = new HttpHeaders();\n new Headers(init.headers).forEach((value, key) => (headers = headers.set(key, value)));\n\n let subscription: Subscription | undefined;\n const onAbort = () => {\n subscription?.unsubscribe();\n reject(signal?.reason);\n };\n const done = () => signal?.removeEventListener('abort', onAbort);\n signal?.addEventListener('abort', onAbort, { once: true });\n\n subscription = http\n .request(init.method ?? 'GET', input instanceof Request ? input.url : String(input), {\n body: init.body ?? null,\n headers,\n withCredentials: init.credentials === 'include',\n observe: 'response',\n // not 'blob': the SSR transfer cache stores blob bodies as an empty string\n responseType: 'arraybuffer',\n // keep the list total when the app enables the transfer cache\n transferCache: { includeHeaders: ['x-total-count'] },\n })\n .subscribe({\n next: (res) => {\n done();\n toResponse(res.status, res.statusText, res.headers, res.body).then(resolve, reject);\n },\n error: (err: unknown) => {\n done();\n if (err instanceof HttpErrorResponse && err.status >= 200) {\n toResponse(err.status, err.statusText, err.headers, err.error).then(resolve, reject);\n } else {\n reject(new TypeError('Failed to fetch', { cause: err }));\n }\n },\n });\n });\n}\n\nasync function toResponse(\n status: number,\n statusText: string,\n httpHeaders: HttpHeaders,\n body: unknown,\n): Promise<Response> {\n const headers = new Headers();\n for (const key of httpHeaders.keys()) {\n for (const value of httpHeaders.getAll(key) ?? []) headers.append(key, value);\n }\n const noBody = status === 204 || status === 205 || status === 304;\n return new Response(noBody ? null : await toBodyInit(body), { status, statusText, headers });\n}\n\n/**\n * Blob → its bytes (read through `arrayBuffer()`, so a Blob of another realm or polyfill works);\n * text / buffer as is; anything an interceptor turned into an object goes back to JSON.\n */\nasync function toBodyInit(body: unknown): Promise<BodyInit | null> {\n if (body === null || body === undefined) return null;\n if (typeof body === 'string' || body instanceof ArrayBuffer) return body;\n if (typeof (body as Blob).arrayBuffer === 'function') return (body as Blob).arrayBuffer();\n return JSON.stringify(body);\n}\n","import { PendingTasks } from '@angular/core';\nimport {\n Skill3Http,\n type HttpMethod,\n type RequestOptions,\n type RequestTarget,\n type ResolvedSkill3Config,\n type SessionStore,\n type Skill3Response,\n type Skill3State,\n} from '@skill3/sdk-core';\n\n/**\n * `Skill3Http` that keeps the app unstable while a request runs (retries and token renewals\n * included). Zoneless SSR waits only for `PendingTasks`, and the library awaits storage before\n * `HttpClient` registers its own task, so without this the page renders before the data arrives.\n */\nexport class PendingTasksHttp extends Skill3Http {\n constructor(\n config: ResolvedSkill3Config,\n store: SessionStore,\n state: Skill3State,\n private readonly tasks: PendingTasks,\n ) {\n super(config, store, state);\n }\n\n override request<T = any>(\n method: HttpMethod,\n target: RequestTarget,\n option?: RequestOptions,\n ): Promise<Skill3Response<T>> {\n // add() rather than run(): run() returns nothing and reports rejections to the ErrorHandler\n const done = this.tasks.add();\n return super.request<T>(method, target, option).finally(done);\n }\n}\n","import { DestroyRef, Signal } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport {\n AuthService as BaseAuthService,\n CoreSiteService as BaseCoreSiteService,\n type AuthKeyOption,\n type Skill3Client,\n} from '@skill3/sdk-core';\nimport { valueToObservable, valueToSignal } from './interop';\n\n/**\n * `AuthService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.\n * Inject it: `inject(AuthService)` (registered by `provideSkill3()`).\n */\nexport class AuthService extends BaseAuthService {\n /** Signed-in user as a signal (`null` when signed out). */\n readonly user: Signal<any>;\n /** Signed-in user as an observable (`null` when signed out). Emits the current user on subscribe. */\n readonly user$: Observable<any>;\n\n constructor(client: Skill3Client, destroyRef: DestroyRef) {\n super(client.config, client.http, client.store, client.state);\n this.user = valueToSignal(client.state.user, destroyRef);\n this.user$ = valueToObservable(client.state.user);\n }\n\n /** Emits the stored user (when `dispatch`) and returns `user$`. */\n async subscribeUser({\n prefix_key,\n dispatch = true,\n }: AuthKeyOption & { dispatch?: boolean } = {}): Promise<Observable<any>> {\n const user = await this.getUser({ prefix_key });\n if (dispatch) this.state.setUser(user);\n return this.user$;\n }\n}\n\n/**\n * `CoreSiteService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.\n * Inject it: `inject(CoreSiteService)` (registered by `provideSkill3()`).\n */\nexport class CoreSiteService extends BaseCoreSiteService {\n /** true once a site token is known. */\n readonly siteReady: Signal<boolean>;\n\n constructor(client: Skill3Client, auth: AuthService, destroyRef: DestroyRef) {\n super(client.config, client.http, client.store, client.state, auth);\n this.siteReady = valueToSignal(client.state.siteReady, destroyRef);\n }\n\n /** Emits `true` now and every time an automatic site-token renewal finishes. */\n onSiteTokenRenew(): Observable<boolean> {\n return new Observable<boolean>((subscriber) =>\n this.state.onSiteRenewed((renewed) => subscriber.next(renewed)),\n );\n }\n}\n","import { DestroyRef, Signal, signal } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport type { ReadonlyValue } from '@skill3/sdk-core';\n\n/** Signal that follows `value` until `destroyRef` is destroyed. */\nexport function valueToSignal<T>(value: ReadonlyValue<T>, destroyRef: DestroyRef): Signal<T> {\n const result = signal(value.get());\n destroyRef.onDestroy(value.subscribe((next) => result.set(next)));\n return result.asReadonly();\n}\n\n/** Observable that emits the current value on subscribe, then every change (like `BehaviorSubject`). */\nexport function valueToObservable<T>(value: ReadonlyValue<T>): Observable<T> {\n return new Observable<T>((subscriber) => {\n subscriber.next(value.get());\n return value.subscribe((next) => subscriber.next(next));\n });\n}\n","import { PLATFORM_ID, Provider, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n CustomStorageProvider,\n LocalStorageProvider,\n type StorageLike,\n type StorageProvider as CoreStorageProvider,\n} from '@skill3/sdk-core';\n\n/**\n * DI token of the storage the library keeps tokens and cached user/site in:\n * `{ provide: StorageProvider, useClass: MyStorage }`. Any class with the methods works\n * (the storages of `@skill3/sdk-core` included), extending this one is optional.\n */\nexport abstract class StorageProvider implements CoreStorageProvider {\n abstract get(key: string): Promise<string | null>;\n abstract set(key: string, value: string): Promise<unknown>;\n abstract remove(key: string): Promise<unknown>;\n abstract clear(): Promise<void>;\n abstract length(): Promise<number | null>;\n abstract keys(): Promise<string[]>;\n}\n\n/** `storage` option that keeps the session in `localStorage` (memory on the server). */\nexport function provideLocalStorage(): Provider {\n return {\n provide: StorageProvider,\n useFactory: () =>\n new LocalStorageProvider(isPlatformBrowser(inject(PLATFORM_ID)) ? undefined : null),\n };\n}\n\n/**\n * `storage` option that wraps a promise-based storage resolved from DI.\n *\n * ```ts\n * storage: provideCustomStorage(() => {\n * const storage = inject(Storage); // @ionic/storage-angular\n * storage.create();\n * return storage;\n * })\n * ```\n */\nexport function provideCustomStorage(factory: () => StorageLike): Provider {\n return { provide: StorageProvider, useFactory: () => new CustomStorageProvider(factory()) };\n}\n"],"mappings":"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","names":["import_core","import_common","import_http","import_sdk_core","signal","import_rxjs","import_sdk_core","BaseAuthService","BaseCoreSiteService","import_core","import_sdk_core"]}
@@ -0,0 +1,106 @@
1
+ import { Skill3Client, ResolvedSkill3Config, Skill3Config, AuthService as AuthService$1, AuthKeyOption, CoreSiteService as CoreSiteService$1, StorageProvider as StorageProvider$1, StorageLike, ReadonlyValue } from '@skill3/sdk-core';
2
+ export * from '@skill3/sdk-core';
3
+ import { InjectionToken, Provider, EnvironmentProviders, Signal, DestroyRef } from '@angular/core';
4
+ import { Observable } from 'rxjs';
5
+ import { HttpClient } from '@angular/common/http';
6
+
7
+ interface Skill3AngularConfig extends Omit<Skill3Config, 'storage'> {
8
+ /** Storage provider, e.g. `provideLocalStorage()`. Default: in-memory (lost on reload). */
9
+ storage?: Provider;
10
+ /**
11
+ * Default true: send requests through `HttpClient` (interceptors and `withFetch()` of
12
+ * `provideHttpClient()`, SSR transfer cache). false → plain `fetch`. Ignored when `fetch` is set.
13
+ */
14
+ useHttpClient?: boolean;
15
+ }
16
+ /** The `Skill3Client` behind the injectable services. */
17
+ declare const SKILL3_CLIENT: InjectionToken<Skill3Client>;
18
+ /** Config after defaults are applied. */
19
+ declare const SKILL3_CONFIG: InjectionToken<ResolvedSkill3Config>;
20
+ /**
21
+ * Registers the library.
22
+ *
23
+ * ```ts
24
+ * bootstrapApplication(App, {
25
+ * providers: [
26
+ * provideHttpClient(withFetch()),
27
+ * provideSkill3({ scope: 'site', environment, storage: provideLocalStorage() }),
28
+ * ],
29
+ * });
30
+ * ```
31
+ *
32
+ * Pass a factory instead of an object when the config depends on other providers
33
+ * (e.g. SSR request data). The factory runs in an injection context, so it cannot
34
+ * return `storage`: pass the storage provider as the second argument instead.
35
+ */
36
+ declare function provideSkill3(config?: Skill3AngularConfig | (() => Skill3AngularConfig), storageProvider?: Provider): EnvironmentProviders;
37
+
38
+ /**
39
+ * `AuthService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.
40
+ * Inject it: `inject(AuthService)` (registered by `provideSkill3()`).
41
+ */
42
+ declare class AuthService extends AuthService$1 {
43
+ /** Signed-in user as a signal (`null` when signed out). */
44
+ readonly user: Signal<any>;
45
+ /** Signed-in user as an observable (`null` when signed out). Emits the current user on subscribe. */
46
+ readonly user$: Observable<any>;
47
+ constructor(client: Skill3Client, destroyRef: DestroyRef);
48
+ /** Emits the stored user (when `dispatch`) and returns `user$`. */
49
+ subscribeUser({ prefix_key, dispatch, }?: AuthKeyOption & {
50
+ dispatch?: boolean;
51
+ }): Promise<Observable<any>>;
52
+ }
53
+ /**
54
+ * `CoreSiteService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.
55
+ * Inject it: `inject(CoreSiteService)` (registered by `provideSkill3()`).
56
+ */
57
+ declare class CoreSiteService extends CoreSiteService$1 {
58
+ /** true once a site token is known. */
59
+ readonly siteReady: Signal<boolean>;
60
+ constructor(client: Skill3Client, auth: AuthService, destroyRef: DestroyRef);
61
+ /** Emits `true` now and every time an automatic site-token renewal finishes. */
62
+ onSiteTokenRenew(): Observable<boolean>;
63
+ }
64
+
65
+ /**
66
+ * DI token of the storage the library keeps tokens and cached user/site in:
67
+ * `{ provide: StorageProvider, useClass: MyStorage }`. Any class with the methods works
68
+ * (the storages of `@skill3/sdk-core` included), extending this one is optional.
69
+ */
70
+ declare abstract class StorageProvider implements StorageProvider$1 {
71
+ abstract get(key: string): Promise<string | null>;
72
+ abstract set(key: string, value: string): Promise<unknown>;
73
+ abstract remove(key: string): Promise<unknown>;
74
+ abstract clear(): Promise<void>;
75
+ abstract length(): Promise<number | null>;
76
+ abstract keys(): Promise<string[]>;
77
+ }
78
+ /** `storage` option that keeps the session in `localStorage` (memory on the server). */
79
+ declare function provideLocalStorage(): Provider;
80
+ /**
81
+ * `storage` option that wraps a promise-based storage resolved from DI.
82
+ *
83
+ * ```ts
84
+ * storage: provideCustomStorage(() => {
85
+ * const storage = inject(Storage); // @ionic/storage-angular
86
+ * storage.create();
87
+ * return storage;
88
+ * })
89
+ * ```
90
+ */
91
+ declare function provideCustomStorage(factory: () => StorageLike): Provider;
92
+
93
+ /**
94
+ * `fetch` that sends through Angular's `HttpClient`, so the app's interceptors, XSRF handling
95
+ * and the SSR transfer cache still apply. Non-2xx answers resolve as a `Response` (like `fetch`);
96
+ * only network failures reject.
97
+ */
98
+ declare function httpClientFetch(http: HttpClient): typeof fetch;
99
+
100
+ /** Signal that follows `value` until `destroyRef` is destroyed. */
101
+ declare function valueToSignal<T>(value: ReadonlyValue<T>, destroyRef: DestroyRef): Signal<T>;
102
+ /** Observable that emits the current value on subscribe, then every change (like `BehaviorSubject`). */
103
+ declare function valueToObservable<T>(value: ReadonlyValue<T>): Observable<T>;
104
+
105
+ export { AuthService, CoreSiteService, SKILL3_CLIENT, SKILL3_CONFIG, StorageProvider, httpClientFetch, provideCustomStorage, provideLocalStorage, provideSkill3, valueToObservable, valueToSignal };
106
+ export type { Skill3AngularConfig };
@@ -0,0 +1,106 @@
1
+ import { Skill3Client, ResolvedSkill3Config, Skill3Config, AuthService as AuthService$1, AuthKeyOption, CoreSiteService as CoreSiteService$1, StorageProvider as StorageProvider$1, StorageLike, ReadonlyValue } from '@skill3/sdk-core';
2
+ export * from '@skill3/sdk-core';
3
+ import { InjectionToken, Provider, EnvironmentProviders, Signal, DestroyRef } from '@angular/core';
4
+ import { Observable } from 'rxjs';
5
+ import { HttpClient } from '@angular/common/http';
6
+
7
+ interface Skill3AngularConfig extends Omit<Skill3Config, 'storage'> {
8
+ /** Storage provider, e.g. `provideLocalStorage()`. Default: in-memory (lost on reload). */
9
+ storage?: Provider;
10
+ /**
11
+ * Default true: send requests through `HttpClient` (interceptors and `withFetch()` of
12
+ * `provideHttpClient()`, SSR transfer cache). false → plain `fetch`. Ignored when `fetch` is set.
13
+ */
14
+ useHttpClient?: boolean;
15
+ }
16
+ /** The `Skill3Client` behind the injectable services. */
17
+ declare const SKILL3_CLIENT: InjectionToken<Skill3Client>;
18
+ /** Config after defaults are applied. */
19
+ declare const SKILL3_CONFIG: InjectionToken<ResolvedSkill3Config>;
20
+ /**
21
+ * Registers the library.
22
+ *
23
+ * ```ts
24
+ * bootstrapApplication(App, {
25
+ * providers: [
26
+ * provideHttpClient(withFetch()),
27
+ * provideSkill3({ scope: 'site', environment, storage: provideLocalStorage() }),
28
+ * ],
29
+ * });
30
+ * ```
31
+ *
32
+ * Pass a factory instead of an object when the config depends on other providers
33
+ * (e.g. SSR request data). The factory runs in an injection context, so it cannot
34
+ * return `storage`: pass the storage provider as the second argument instead.
35
+ */
36
+ declare function provideSkill3(config?: Skill3AngularConfig | (() => Skill3AngularConfig), storageProvider?: Provider): EnvironmentProviders;
37
+
38
+ /**
39
+ * `AuthService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.
40
+ * Inject it: `inject(AuthService)` (registered by `provideSkill3()`).
41
+ */
42
+ declare class AuthService extends AuthService$1 {
43
+ /** Signed-in user as a signal (`null` when signed out). */
44
+ readonly user: Signal<any>;
45
+ /** Signed-in user as an observable (`null` when signed out). Emits the current user on subscribe. */
46
+ readonly user$: Observable<any>;
47
+ constructor(client: Skill3Client, destroyRef: DestroyRef);
48
+ /** Emits the stored user (when `dispatch`) and returns `user$`. */
49
+ subscribeUser({ prefix_key, dispatch, }?: AuthKeyOption & {
50
+ dispatch?: boolean;
51
+ }): Promise<Observable<any>>;
52
+ }
53
+ /**
54
+ * `CoreSiteService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.
55
+ * Inject it: `inject(CoreSiteService)` (registered by `provideSkill3()`).
56
+ */
57
+ declare class CoreSiteService extends CoreSiteService$1 {
58
+ /** true once a site token is known. */
59
+ readonly siteReady: Signal<boolean>;
60
+ constructor(client: Skill3Client, auth: AuthService, destroyRef: DestroyRef);
61
+ /** Emits `true` now and every time an automatic site-token renewal finishes. */
62
+ onSiteTokenRenew(): Observable<boolean>;
63
+ }
64
+
65
+ /**
66
+ * DI token of the storage the library keeps tokens and cached user/site in:
67
+ * `{ provide: StorageProvider, useClass: MyStorage }`. Any class with the methods works
68
+ * (the storages of `@skill3/sdk-core` included), extending this one is optional.
69
+ */
70
+ declare abstract class StorageProvider implements StorageProvider$1 {
71
+ abstract get(key: string): Promise<string | null>;
72
+ abstract set(key: string, value: string): Promise<unknown>;
73
+ abstract remove(key: string): Promise<unknown>;
74
+ abstract clear(): Promise<void>;
75
+ abstract length(): Promise<number | null>;
76
+ abstract keys(): Promise<string[]>;
77
+ }
78
+ /** `storage` option that keeps the session in `localStorage` (memory on the server). */
79
+ declare function provideLocalStorage(): Provider;
80
+ /**
81
+ * `storage` option that wraps a promise-based storage resolved from DI.
82
+ *
83
+ * ```ts
84
+ * storage: provideCustomStorage(() => {
85
+ * const storage = inject(Storage); // @ionic/storage-angular
86
+ * storage.create();
87
+ * return storage;
88
+ * })
89
+ * ```
90
+ */
91
+ declare function provideCustomStorage(factory: () => StorageLike): Provider;
92
+
93
+ /**
94
+ * `fetch` that sends through Angular's `HttpClient`, so the app's interceptors, XSRF handling
95
+ * and the SSR transfer cache still apply. Non-2xx answers resolve as a `Response` (like `fetch`);
96
+ * only network failures reject.
97
+ */
98
+ declare function httpClientFetch(http: HttpClient): typeof fetch;
99
+
100
+ /** Signal that follows `value` until `destroyRef` is destroyed. */
101
+ declare function valueToSignal<T>(value: ReadonlyValue<T>, destroyRef: DestroyRef): Signal<T>;
102
+ /** Observable that emits the current value on subscribe, then every change (like `BehaviorSubject`). */
103
+ declare function valueToObservable<T>(value: ReadonlyValue<T>): Observable<T>;
104
+
105
+ export { AuthService, CoreSiteService, SKILL3_CLIENT, SKILL3_CONFIG, StorageProvider, httpClientFetch, provideCustomStorage, provideLocalStorage, provideSkill3, valueToObservable, valueToSignal };
106
+ export type { Skill3AngularConfig };
package/dist/index.js ADDED
@@ -0,0 +1,229 @@
1
+ // src/index.ts
2
+ export * from "@skill3/sdk-core";
3
+
4
+ // src/provide.ts
5
+ import {
6
+ DOCUMENT,
7
+ DestroyRef as DestroyRef2,
8
+ InjectionToken,
9
+ PLATFORM_ID as PLATFORM_ID2,
10
+ PendingTasks,
11
+ inject as inject2,
12
+ makeEnvironmentProviders
13
+ } from "@angular/core";
14
+ import { isPlatformServer } from "@angular/common";
15
+ import { HttpClient as HttpClient2 } from "@angular/common/http";
16
+ import {
17
+ CustomService,
18
+ MemoryStorageProvider,
19
+ SessionStore,
20
+ Skill3Http as Skill3Http2,
21
+ Skill3State,
22
+ createSkill3
23
+ } from "@skill3/sdk-core";
24
+
25
+ // src/http-client-fetch.ts
26
+ import { HttpErrorResponse, HttpHeaders } from "@angular/common/http";
27
+ function httpClientFetch(http) {
28
+ return (input, init = {}) => new Promise((resolve, reject) => {
29
+ const signal2 = init.signal;
30
+ if (signal2?.aborted) return reject(signal2.reason);
31
+ let headers = new HttpHeaders();
32
+ new Headers(init.headers).forEach((value, key) => headers = headers.set(key, value));
33
+ let subscription;
34
+ const onAbort = () => {
35
+ subscription?.unsubscribe();
36
+ reject(signal2?.reason);
37
+ };
38
+ const done = () => signal2?.removeEventListener("abort", onAbort);
39
+ signal2?.addEventListener("abort", onAbort, { once: true });
40
+ subscription = http.request(init.method ?? "GET", input instanceof Request ? input.url : String(input), {
41
+ body: init.body ?? null,
42
+ headers,
43
+ withCredentials: init.credentials === "include",
44
+ observe: "response",
45
+ // not 'blob': the SSR transfer cache stores blob bodies as an empty string
46
+ responseType: "arraybuffer",
47
+ // keep the list total when the app enables the transfer cache
48
+ transferCache: { includeHeaders: ["x-total-count"] }
49
+ }).subscribe({
50
+ next: (res) => {
51
+ done();
52
+ toResponse(res.status, res.statusText, res.headers, res.body).then(resolve, reject);
53
+ },
54
+ error: (err) => {
55
+ done();
56
+ if (err instanceof HttpErrorResponse && err.status >= 200) {
57
+ toResponse(err.status, err.statusText, err.headers, err.error).then(resolve, reject);
58
+ } else {
59
+ reject(new TypeError("Failed to fetch", { cause: err }));
60
+ }
61
+ }
62
+ });
63
+ });
64
+ }
65
+ async function toResponse(status, statusText, httpHeaders, body) {
66
+ const headers = new Headers();
67
+ for (const key of httpHeaders.keys()) {
68
+ for (const value of httpHeaders.getAll(key) ?? []) headers.append(key, value);
69
+ }
70
+ const noBody = status === 204 || status === 205 || status === 304;
71
+ return new Response(noBody ? null : await toBodyInit(body), { status, statusText, headers });
72
+ }
73
+ async function toBodyInit(body) {
74
+ if (body === null || body === void 0) return null;
75
+ if (typeof body === "string" || body instanceof ArrayBuffer) return body;
76
+ if (typeof body.arrayBuffer === "function") return body.arrayBuffer();
77
+ return JSON.stringify(body);
78
+ }
79
+
80
+ // src/pending-tasks-http.ts
81
+ import {
82
+ Skill3Http
83
+ } from "@skill3/sdk-core";
84
+ var PendingTasksHttp = class extends Skill3Http {
85
+ constructor(config, store, state, tasks) {
86
+ super(config, store, state);
87
+ this.tasks = tasks;
88
+ }
89
+ tasks;
90
+ request(method, target, option) {
91
+ const done = this.tasks.add();
92
+ return super.request(method, target, option).finally(done);
93
+ }
94
+ };
95
+
96
+ // src/services.ts
97
+ import { Observable as Observable2 } from "rxjs";
98
+ import {
99
+ AuthService as BaseAuthService,
100
+ CoreSiteService as BaseCoreSiteService
101
+ } from "@skill3/sdk-core";
102
+
103
+ // src/interop.ts
104
+ import { signal } from "@angular/core";
105
+ import { Observable } from "rxjs";
106
+ function valueToSignal(value, destroyRef) {
107
+ const result = signal(value.get());
108
+ destroyRef.onDestroy(value.subscribe((next) => result.set(next)));
109
+ return result.asReadonly();
110
+ }
111
+ function valueToObservable(value) {
112
+ return new Observable((subscriber) => {
113
+ subscriber.next(value.get());
114
+ return value.subscribe((next) => subscriber.next(next));
115
+ });
116
+ }
117
+
118
+ // src/services.ts
119
+ var AuthService = class extends BaseAuthService {
120
+ /** Signed-in user as a signal (`null` when signed out). */
121
+ user;
122
+ /** Signed-in user as an observable (`null` when signed out). Emits the current user on subscribe. */
123
+ user$;
124
+ constructor(client, destroyRef) {
125
+ super(client.config, client.http, client.store, client.state);
126
+ this.user = valueToSignal(client.state.user, destroyRef);
127
+ this.user$ = valueToObservable(client.state.user);
128
+ }
129
+ /** Emits the stored user (when `dispatch`) and returns `user$`. */
130
+ async subscribeUser({
131
+ prefix_key,
132
+ dispatch = true
133
+ } = {}) {
134
+ const user = await this.getUser({ prefix_key });
135
+ if (dispatch) this.state.setUser(user);
136
+ return this.user$;
137
+ }
138
+ };
139
+ var CoreSiteService = class extends BaseCoreSiteService {
140
+ /** true once a site token is known. */
141
+ siteReady;
142
+ constructor(client, auth, destroyRef) {
143
+ super(client.config, client.http, client.store, client.state, auth);
144
+ this.siteReady = valueToSignal(client.state.siteReady, destroyRef);
145
+ }
146
+ /** Emits `true` now and every time an automatic site-token renewal finishes. */
147
+ onSiteTokenRenew() {
148
+ return new Observable2(
149
+ (subscriber) => this.state.onSiteRenewed((renewed) => subscriber.next(renewed))
150
+ );
151
+ }
152
+ };
153
+
154
+ // src/storage.ts
155
+ import { PLATFORM_ID, inject } from "@angular/core";
156
+ import { isPlatformBrowser } from "@angular/common";
157
+ import {
158
+ CustomStorageProvider,
159
+ LocalStorageProvider
160
+ } from "@skill3/sdk-core";
161
+ var StorageProvider = class {
162
+ };
163
+ function provideLocalStorage() {
164
+ return {
165
+ provide: StorageProvider,
166
+ useFactory: () => new LocalStorageProvider(isPlatformBrowser(inject(PLATFORM_ID)) ? void 0 : null)
167
+ };
168
+ }
169
+ function provideCustomStorage(factory) {
170
+ return { provide: StorageProvider, useFactory: () => new CustomStorageProvider(factory()) };
171
+ }
172
+
173
+ // src/provide.ts
174
+ var SKILL3_CLIENT = new InjectionToken("SKILL3_CLIENT");
175
+ var SKILL3_CONFIG = new InjectionToken("SKILL3_CONFIG");
176
+ function provideSkill3(config = {}, storageProvider) {
177
+ const storage = storageProvider ?? (typeof config === "function" ? void 0 : config.storage);
178
+ const client = () => inject2(SKILL3_CLIENT);
179
+ return makeEnvironmentProviders([
180
+ {
181
+ provide: SKILL3_CLIENT,
182
+ useFactory: () => createClient(typeof config === "function" ? config() : config)
183
+ },
184
+ storage ?? { provide: StorageProvider, useClass: MemoryStorageProvider },
185
+ { provide: SKILL3_CONFIG, useFactory: () => client().config },
186
+ { provide: Skill3State, useFactory: () => client().state },
187
+ { provide: SessionStore, useFactory: () => client().store },
188
+ { provide: Skill3Http2, useFactory: () => client().http },
189
+ { provide: AuthService, useFactory: () => new AuthService(client(), inject2(DestroyRef2)) },
190
+ {
191
+ provide: CoreSiteService,
192
+ useFactory: () => new CoreSiteService(client(), inject2(AuthService), inject2(DestroyRef2))
193
+ },
194
+ { provide: CustomService, useFactory: () => new CustomService(client().http) }
195
+ ]);
196
+ }
197
+ function createClient({
198
+ storage: _storage,
199
+ useHttpClient = true,
200
+ ...config
201
+ }) {
202
+ const fetch = config.fetch ?? (useHttpClient ? httpClientFetch(inject2(HttpClient2)) : void 0);
203
+ const document = inject2(DOCUMENT, { optional: true });
204
+ const tasks = inject2(PendingTasks);
205
+ return createSkill3(
206
+ {
207
+ ...config,
208
+ storage: inject2(StorageProvider),
209
+ isServer: config.isServer ?? isPlatformServer(inject2(PLATFORM_ID2)),
210
+ fetch,
211
+ hostname: config.hostname ?? (() => document?.location?.hostname)
212
+ },
213
+ { createHttp: (...args) => new PendingTasksHttp(...args, tasks) }
214
+ );
215
+ }
216
+ export {
217
+ AuthService,
218
+ CoreSiteService,
219
+ SKILL3_CLIENT,
220
+ SKILL3_CONFIG,
221
+ StorageProvider,
222
+ httpClientFetch,
223
+ provideCustomStorage,
224
+ provideLocalStorage,
225
+ provideSkill3,
226
+ valueToObservable,
227
+ valueToSignal
228
+ };
229
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/provide.ts","../src/http-client-fetch.ts","../src/pending-tasks-http.ts","../src/services.ts","../src/interop.ts","../src/storage.ts"],"sourcesContent":["/*\n * Public API Surface of @skill3/sdk-angular\n */\n\n// everything of the core; the local exports below replace the core ones with the same name\nexport * from '@skill3/sdk-core';\n\nexport { provideSkill3, SKILL3_CLIENT, SKILL3_CONFIG } from './provide';\nexport type { Skill3AngularConfig } from './provide';\nexport { AuthService, CoreSiteService } from './services';\nexport { StorageProvider, provideLocalStorage, provideCustomStorage } from './storage';\nexport { httpClientFetch } from './http-client-fetch';\nexport { valueToObservable, valueToSignal } from './interop';\n","import {\n DOCUMENT,\n DestroyRef,\n EnvironmentProviders,\n InjectionToken,\n PLATFORM_ID,\n PendingTasks,\n Provider,\n inject,\n makeEnvironmentProviders,\n} from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport { HttpClient } from '@angular/common/http';\nimport {\n CustomService,\n MemoryStorageProvider,\n SessionStore,\n Skill3Http,\n Skill3State,\n createSkill3,\n type ResolvedSkill3Config,\n type Skill3Client,\n type Skill3Config,\n} from '@skill3/sdk-core';\nimport { httpClientFetch } from './http-client-fetch';\nimport { PendingTasksHttp } from './pending-tasks-http';\nimport { AuthService, CoreSiteService } from './services';\nimport { StorageProvider } from './storage';\n\nexport interface Skill3AngularConfig extends Omit<Skill3Config, 'storage'> {\n /** Storage provider, e.g. `provideLocalStorage()`. Default: in-memory (lost on reload). */\n storage?: Provider;\n /**\n * Default true: send requests through `HttpClient` (interceptors and `withFetch()` of\n * `provideHttpClient()`, SSR transfer cache). false → plain `fetch`. Ignored when `fetch` is set.\n */\n useHttpClient?: boolean;\n}\n\n/** The `Skill3Client` behind the injectable services. */\nexport const SKILL3_CLIENT = new InjectionToken<Skill3Client>('SKILL3_CLIENT');\n\n/** Config after defaults are applied. */\nexport const SKILL3_CONFIG = new InjectionToken<ResolvedSkill3Config>('SKILL3_CONFIG');\n\n/**\n * Registers the library.\n *\n * ```ts\n * bootstrapApplication(App, {\n * providers: [\n * provideHttpClient(withFetch()),\n * provideSkill3({ scope: 'site', environment, storage: provideLocalStorage() }),\n * ],\n * });\n * ```\n *\n * Pass a factory instead of an object when the config depends on other providers\n * (e.g. SSR request data). The factory runs in an injection context, so it cannot\n * return `storage`: pass the storage provider as the second argument instead.\n */\nexport function provideSkill3(\n config: Skill3AngularConfig | (() => Skill3AngularConfig) = {},\n storageProvider?: Provider,\n): EnvironmentProviders {\n const storage = storageProvider ?? (typeof config === 'function' ? undefined : config.storage);\n const client = () => inject(SKILL3_CLIENT);\n return makeEnvironmentProviders([\n {\n provide: SKILL3_CLIENT,\n useFactory: () => createClient(typeof config === 'function' ? config() : config),\n },\n storage ?? { provide: StorageProvider, useClass: MemoryStorageProvider },\n { provide: SKILL3_CONFIG, useFactory: () => client().config },\n { provide: Skill3State, useFactory: () => client().state },\n { provide: SessionStore, useFactory: () => client().store },\n { provide: Skill3Http, useFactory: () => client().http },\n { provide: AuthService, useFactory: () => new AuthService(client(), inject(DestroyRef)) },\n {\n provide: CoreSiteService,\n useFactory: () => new CoreSiteService(client(), inject(AuthService), inject(DestroyRef)),\n },\n { provide: CustomService, useFactory: () => new CustomService(client().http) },\n ]);\n}\n\nfunction createClient({\n storage: _storage,\n useHttpClient = true,\n ...config\n}: Skill3AngularConfig): Skill3Client {\n // HttpClient is provided in root (Angular 22), provideHttpClient() only configures it\n const fetch = config.fetch ?? (useHttpClient ? httpClientFetch(inject(HttpClient)) : undefined);\n const document = inject(DOCUMENT, { optional: true });\n const tasks = inject(PendingTasks);\n return createSkill3(\n {\n ...config,\n storage: inject(StorageProvider),\n isServer: config.isServer ?? isPlatformServer(inject(PLATFORM_ID)),\n fetch,\n hostname: config.hostname ?? (() => document?.location?.hostname),\n },\n { createHttp: (...args) => new PendingTasksHttp(...args, tasks) },\n );\n}\n","import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';\nimport type { Subscription } from 'rxjs';\n\n/**\n * `fetch` that sends through Angular's `HttpClient`, so the app's interceptors, XSRF handling\n * and the SSR transfer cache still apply. Non-2xx answers resolve as a `Response` (like `fetch`);\n * only network failures reject.\n */\nexport function httpClientFetch(http: HttpClient): typeof fetch {\n return (input, init = {}) =>\n new Promise<Response>((resolve, reject) => {\n const signal = init.signal;\n if (signal?.aborted) return reject(signal.reason);\n\n let headers = new HttpHeaders();\n new Headers(init.headers).forEach((value, key) => (headers = headers.set(key, value)));\n\n let subscription: Subscription | undefined;\n const onAbort = () => {\n subscription?.unsubscribe();\n reject(signal?.reason);\n };\n const done = () => signal?.removeEventListener('abort', onAbort);\n signal?.addEventListener('abort', onAbort, { once: true });\n\n subscription = http\n .request(init.method ?? 'GET', input instanceof Request ? input.url : String(input), {\n body: init.body ?? null,\n headers,\n withCredentials: init.credentials === 'include',\n observe: 'response',\n // not 'blob': the SSR transfer cache stores blob bodies as an empty string\n responseType: 'arraybuffer',\n // keep the list total when the app enables the transfer cache\n transferCache: { includeHeaders: ['x-total-count'] },\n })\n .subscribe({\n next: (res) => {\n done();\n toResponse(res.status, res.statusText, res.headers, res.body).then(resolve, reject);\n },\n error: (err: unknown) => {\n done();\n if (err instanceof HttpErrorResponse && err.status >= 200) {\n toResponse(err.status, err.statusText, err.headers, err.error).then(resolve, reject);\n } else {\n reject(new TypeError('Failed to fetch', { cause: err }));\n }\n },\n });\n });\n}\n\nasync function toResponse(\n status: number,\n statusText: string,\n httpHeaders: HttpHeaders,\n body: unknown,\n): Promise<Response> {\n const headers = new Headers();\n for (const key of httpHeaders.keys()) {\n for (const value of httpHeaders.getAll(key) ?? []) headers.append(key, value);\n }\n const noBody = status === 204 || status === 205 || status === 304;\n return new Response(noBody ? null : await toBodyInit(body), { status, statusText, headers });\n}\n\n/**\n * Blob → its bytes (read through `arrayBuffer()`, so a Blob of another realm or polyfill works);\n * text / buffer as is; anything an interceptor turned into an object goes back to JSON.\n */\nasync function toBodyInit(body: unknown): Promise<BodyInit | null> {\n if (body === null || body === undefined) return null;\n if (typeof body === 'string' || body instanceof ArrayBuffer) return body;\n if (typeof (body as Blob).arrayBuffer === 'function') return (body as Blob).arrayBuffer();\n return JSON.stringify(body);\n}\n","import { PendingTasks } from '@angular/core';\nimport {\n Skill3Http,\n type HttpMethod,\n type RequestOptions,\n type RequestTarget,\n type ResolvedSkill3Config,\n type SessionStore,\n type Skill3Response,\n type Skill3State,\n} from '@skill3/sdk-core';\n\n/**\n * `Skill3Http` that keeps the app unstable while a request runs (retries and token renewals\n * included). Zoneless SSR waits only for `PendingTasks`, and the library awaits storage before\n * `HttpClient` registers its own task, so without this the page renders before the data arrives.\n */\nexport class PendingTasksHttp extends Skill3Http {\n constructor(\n config: ResolvedSkill3Config,\n store: SessionStore,\n state: Skill3State,\n private readonly tasks: PendingTasks,\n ) {\n super(config, store, state);\n }\n\n override request<T = any>(\n method: HttpMethod,\n target: RequestTarget,\n option?: RequestOptions,\n ): Promise<Skill3Response<T>> {\n // add() rather than run(): run() returns nothing and reports rejections to the ErrorHandler\n const done = this.tasks.add();\n return super.request<T>(method, target, option).finally(done);\n }\n}\n","import { DestroyRef, Signal } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport {\n AuthService as BaseAuthService,\n CoreSiteService as BaseCoreSiteService,\n type AuthKeyOption,\n type Skill3Client,\n} from '@skill3/sdk-core';\nimport { valueToObservable, valueToSignal } from './interop';\n\n/**\n * `AuthService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.\n * Inject it: `inject(AuthService)` (registered by `provideSkill3()`).\n */\nexport class AuthService extends BaseAuthService {\n /** Signed-in user as a signal (`null` when signed out). */\n readonly user: Signal<any>;\n /** Signed-in user as an observable (`null` when signed out). Emits the current user on subscribe. */\n readonly user$: Observable<any>;\n\n constructor(client: Skill3Client, destroyRef: DestroyRef) {\n super(client.config, client.http, client.store, client.state);\n this.user = valueToSignal(client.state.user, destroyRef);\n this.user$ = valueToObservable(client.state.user);\n }\n\n /** Emits the stored user (when `dispatch`) and returns `user$`. */\n async subscribeUser({\n prefix_key,\n dispatch = true,\n }: AuthKeyOption & { dispatch?: boolean } = {}): Promise<Observable<any>> {\n const user = await this.getUser({ prefix_key });\n if (dispatch) this.state.setUser(user);\n return this.user$;\n }\n}\n\n/**\n * `CoreSiteService` of `@skill3/sdk-core` with the signal / observable API of ngx-core.\n * Inject it: `inject(CoreSiteService)` (registered by `provideSkill3()`).\n */\nexport class CoreSiteService extends BaseCoreSiteService {\n /** true once a site token is known. */\n readonly siteReady: Signal<boolean>;\n\n constructor(client: Skill3Client, auth: AuthService, destroyRef: DestroyRef) {\n super(client.config, client.http, client.store, client.state, auth);\n this.siteReady = valueToSignal(client.state.siteReady, destroyRef);\n }\n\n /** Emits `true` now and every time an automatic site-token renewal finishes. */\n onSiteTokenRenew(): Observable<boolean> {\n return new Observable<boolean>((subscriber) =>\n this.state.onSiteRenewed((renewed) => subscriber.next(renewed)),\n );\n }\n}\n","import { DestroyRef, Signal, signal } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport type { ReadonlyValue } from '@skill3/sdk-core';\n\n/** Signal that follows `value` until `destroyRef` is destroyed. */\nexport function valueToSignal<T>(value: ReadonlyValue<T>, destroyRef: DestroyRef): Signal<T> {\n const result = signal(value.get());\n destroyRef.onDestroy(value.subscribe((next) => result.set(next)));\n return result.asReadonly();\n}\n\n/** Observable that emits the current value on subscribe, then every change (like `BehaviorSubject`). */\nexport function valueToObservable<T>(value: ReadonlyValue<T>): Observable<T> {\n return new Observable<T>((subscriber) => {\n subscriber.next(value.get());\n return value.subscribe((next) => subscriber.next(next));\n });\n}\n","import { PLATFORM_ID, Provider, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n CustomStorageProvider,\n LocalStorageProvider,\n type StorageLike,\n type StorageProvider as CoreStorageProvider,\n} from '@skill3/sdk-core';\n\n/**\n * DI token of the storage the library keeps tokens and cached user/site in:\n * `{ provide: StorageProvider, useClass: MyStorage }`. Any class with the methods works\n * (the storages of `@skill3/sdk-core` included), extending this one is optional.\n */\nexport abstract class StorageProvider implements CoreStorageProvider {\n abstract get(key: string): Promise<string | null>;\n abstract set(key: string, value: string): Promise<unknown>;\n abstract remove(key: string): Promise<unknown>;\n abstract clear(): Promise<void>;\n abstract length(): Promise<number | null>;\n abstract keys(): Promise<string[]>;\n}\n\n/** `storage` option that keeps the session in `localStorage` (memory on the server). */\nexport function provideLocalStorage(): Provider {\n return {\n provide: StorageProvider,\n useFactory: () =>\n new LocalStorageProvider(isPlatformBrowser(inject(PLATFORM_ID)) ? undefined : null),\n };\n}\n\n/**\n * `storage` option that wraps a promise-based storage resolved from DI.\n *\n * ```ts\n * storage: provideCustomStorage(() => {\n * const storage = inject(Storage); // @ionic/storage-angular\n * storage.create();\n * return storage;\n * })\n * ```\n */\nexport function provideCustomStorage(factory: () => StorageLike): Provider {\n return { provide: StorageProvider, useFactory: () => new CustomStorageProvider(factory()) };\n}\n"],"mappings":"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","names":["DestroyRef","PLATFORM_ID","inject","HttpClient","Skill3Http","signal","Observable","Observable","inject","Skill3Http","DestroyRef","HttpClient","PLATFORM_ID"]}
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@skill3/sdk-angular",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Angular bindings for @skill3/sdk-core (successor of @digione/ngx-core): provideSkill3, injectable services with signals and observables",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "typecheck": "tsc -p tsconfig.json"
26
+ },
27
+ "dependencies": {
28
+ "@skill3/sdk-core": "^0.1.0"
29
+ },
30
+ "peerDependencies": {
31
+ "@angular/common": "^22.0.0",
32
+ "@angular/core": "^22.0.0",
33
+ "rxjs": "^7.4.0"
34
+ },
35
+ "devDependencies": {
36
+ "@angular/common": "^22.2.3",
37
+ "@angular/compiler": "^22.2.3",
38
+ "@angular/core": "^22.2.3",
39
+ "@angular/platform-browser": "^22.2.3",
40
+ "rxjs": "~7.8.0"
41
+ }
42
+ }