@nextsparkjs/mobile 0.1.0-beta.1 → 0.1.0-beta.76

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
@@ -2,6 +2,34 @@
2
2
 
3
3
  Mobile app infrastructure for NextSpark. Provides API client, authentication providers, and utilities for building Expo apps that connect to your NextSpark backend.
4
4
 
5
+ ## Repository Structure
6
+
7
+ When developing the package, it's important to understand the different directories:
8
+
9
+ ```
10
+ packages/mobile/
11
+ ├── src/ # Package source code (published to npm)
12
+ │ ├── api/ # API client and entity factory
13
+ │ ├── providers/ # AuthProvider, QueryProvider
14
+ │ ├── hooks/ # useAuth hook
15
+ │ └── lib/ # Storage, Alert utilities
16
+ ├── templates/ # Scaffolding templates for `nextspark add:mobile`
17
+ │ ├── app/ # Expo Router pages
18
+ │ └── src/ # Example entities and components
19
+ └── dist/ # Compiled output
20
+
21
+ apps/mobile/ # Monorepo development app (NOT distributed)
22
+ ├── app/ # Uses local source for development
23
+ └── src/ # Local copies for hot reload & debugging
24
+ ```
25
+
26
+ **Key distinction:**
27
+ - **`packages/mobile/src/`** → Published to npm as `@nextsparkjs/mobile`
28
+ - **`packages/mobile/templates/`** → Copied to user projects via `nextspark add:mobile`
29
+ - **`apps/mobile/`** → Internal dev app with local source (for package development)
30
+
31
+ The templates correctly use `@nextsparkjs/mobile` imports, while `apps/mobile` uses local paths for development convenience.
32
+
5
33
  ## Installation
6
34
 
7
35
  ```bash
@@ -22,17 +22,17 @@ import '../client.types.js';
22
22
  * ```typescript
23
23
  * const tasksApi = createEntityApi<Task, CreateTaskInput, UpdateTaskInput>('tasks')
24
24
  *
25
- * // List tasks
25
+ * // List tasks (returns PaginatedResponse)
26
26
  * const { data, meta } = await tasksApi.list({ page: 1, limit: 10 })
27
27
  *
28
- * // Get single task
29
- * const { data: task } = await tasksApi.get('task-id')
28
+ * // Get single task (returns entity directly)
29
+ * const task = await tasksApi.get('task-id')
30
30
  *
31
- * // Create task
32
- * const { data: newTask } = await tasksApi.create({ title: 'New Task' })
31
+ * // Create task (returns entity directly)
32
+ * const newTask = await tasksApi.create({ title: 'New Task' })
33
33
  *
34
- * // Update task
35
- * const { data: updated } = await tasksApi.update('task-id', { status: 'done' })
34
+ * // Update task (returns entity directly)
35
+ * const updated = await tasksApi.update('task-id', { status: 'done' })
36
36
  *
37
37
  * // Delete task
38
38
  * await tasksApi.delete('task-id')
@@ -4,20 +4,33 @@ function createEntityApi(entityPath) {
4
4
  return {
5
5
  /**
6
6
  * List entities with pagination and filters
7
+ * Returns PaginatedResponse with data array and meta
7
8
  */
8
9
  list: (params) => apiClient.get(basePath, params),
9
10
  /**
10
11
  * Get a single entity by ID
12
+ * Returns the entity directly (unwrapped from SingleResponse)
11
13
  */
12
- get: (id) => apiClient.get(`${basePath}/${id}`),
14
+ get: async (id) => {
15
+ const response = await apiClient.get(`${basePath}/${id}`);
16
+ return response.data;
17
+ },
13
18
  /**
14
19
  * Create a new entity
20
+ * Returns the created entity directly (unwrapped from SingleResponse)
15
21
  */
16
- create: (data) => apiClient.post(basePath, data),
22
+ create: async (data) => {
23
+ const response = await apiClient.post(basePath, data);
24
+ return response.data;
25
+ },
17
26
  /**
18
27
  * Update an existing entity
28
+ * Returns the updated entity directly (unwrapped from SingleResponse)
19
29
  */
20
- update: (id, data) => apiClient.patch(`${basePath}/${id}`, data),
30
+ update: async (id, data) => {
31
+ const response = await apiClient.patch(`${basePath}/${id}`, data);
32
+ return response.data;
33
+ },
21
34
  /**
22
35
  * Delete an entity
23
36
  * Returns void (no content expected from DELETE operations)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/api/entities/factory.ts"],"sourcesContent":["/**\n * Entity API Factory\n *\n * Factory function to create typed API clients for any entity.\n * Follows the same pattern as BaseEntityService in NextSpark web.\n */\n\nimport { apiClient } from '../client'\nimport type { PaginatedResponse, SingleResponse } from '../client.types'\nimport type { EntityApi, EntityListParams } from './types'\n\n/**\n * Create an API client for an entity\n *\n * @param entityPath - The entity path (e.g., 'tasks', 'customers')\n * @returns Typed API client with CRUD operations\n *\n * Note: This factory assumes entities have an `id: string` field for get/update/delete operations.\n * We intentionally don't enforce this via generic constraints to maintain flexibility for\n * entities with different ID field names or types.\n *\n * @example\n * ```typescript\n * const tasksApi = createEntityApi<Task, CreateTaskInput, UpdateTaskInput>('tasks')\n *\n * // List tasks\n * const { data, meta } = await tasksApi.list({ page: 1, limit: 10 })\n *\n * // Get single task\n * const { data: task } = await tasksApi.get('task-id')\n *\n * // Create task\n * const { data: newTask } = await tasksApi.create({ title: 'New Task' })\n *\n * // Update task\n * const { data: updated } = await tasksApi.update('task-id', { status: 'done' })\n *\n * // Delete task\n * await tasksApi.delete('task-id')\n * ```\n */\nexport function createEntityApi<T, CreateInput = Partial<T>, UpdateInput = Partial<T>>(\n entityPath: string\n): EntityApi<T, CreateInput, UpdateInput> {\n const basePath = `/api/v1/${entityPath}`\n\n return {\n /**\n * List entities with pagination and filters\n */\n list: (params?: EntityListParams) =>\n apiClient.get<PaginatedResponse<T>>(basePath, params),\n\n /**\n * Get a single entity by ID\n */\n get: (id: string) =>\n apiClient.get<SingleResponse<T>>(`${basePath}/${id}`),\n\n /**\n * Create a new entity\n */\n create: (data: CreateInput) =>\n apiClient.post<SingleResponse<T>>(basePath, data),\n\n /**\n * Update an existing entity\n */\n update: (id: string, data: UpdateInput) =>\n apiClient.patch<SingleResponse<T>>(`${basePath}/${id}`, data),\n\n /**\n * Delete an entity\n * Returns void (no content expected from DELETE operations)\n */\n delete: (id: string): Promise<void> =>\n apiClient.delete<void>(`${basePath}/${id}`),\n }\n}\n"],"mappings":"AAOA,SAAS,iBAAiB;AAkCnB,SAAS,gBACd,YACwC;AACxC,QAAM,WAAW,WAAW,UAAU;AAEtC,SAAO;AAAA;AAAA;AAAA;AAAA,IAIL,MAAM,CAAC,WACL,UAAU,IAA0B,UAAU,MAAM;AAAA;AAAA;AAAA;AAAA,IAKtD,KAAK,CAAC,OACJ,UAAU,IAAuB,GAAG,QAAQ,IAAI,EAAE,EAAE;AAAA;AAAA;AAAA;AAAA,IAKtD,QAAQ,CAAC,SACP,UAAU,KAAwB,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA,IAKlD,QAAQ,CAAC,IAAY,SACnB,UAAU,MAAyB,GAAG,QAAQ,IAAI,EAAE,IAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,IAM9D,QAAQ,CAAC,OACP,UAAU,OAAa,GAAG,QAAQ,IAAI,EAAE,EAAE;AAAA,EAC9C;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/api/entities/factory.ts"],"sourcesContent":["/**\n * Entity API Factory\n *\n * Factory function to create typed API clients for any entity.\n * Follows the same pattern as BaseEntityService in NextSpark web.\n */\n\nimport { apiClient } from '../client'\nimport type { PaginatedResponse, SingleResponse } from '../client.types'\nimport type { EntityApi, EntityListParams } from './types'\n\n/**\n * Create an API client for an entity\n *\n * @param entityPath - The entity path (e.g., 'tasks', 'customers')\n * @returns Typed API client with CRUD operations\n *\n * Note: This factory assumes entities have an `id: string` field for get/update/delete operations.\n * We intentionally don't enforce this via generic constraints to maintain flexibility for\n * entities with different ID field names or types.\n *\n * @example\n * ```typescript\n * const tasksApi = createEntityApi<Task, CreateTaskInput, UpdateTaskInput>('tasks')\n *\n * // List tasks (returns PaginatedResponse)\n * const { data, meta } = await tasksApi.list({ page: 1, limit: 10 })\n *\n * // Get single task (returns entity directly)\n * const task = await tasksApi.get('task-id')\n *\n * // Create task (returns entity directly)\n * const newTask = await tasksApi.create({ title: 'New Task' })\n *\n * // Update task (returns entity directly)\n * const updated = await tasksApi.update('task-id', { status: 'done' })\n *\n * // Delete task\n * await tasksApi.delete('task-id')\n * ```\n */\nexport function createEntityApi<T, CreateInput = Partial<T>, UpdateInput = Partial<T>>(\n entityPath: string\n): EntityApi<T, CreateInput, UpdateInput> {\n const basePath = `/api/v1/${entityPath}`\n\n return {\n /**\n * List entities with pagination and filters\n * Returns PaginatedResponse with data array and meta\n */\n list: (params?: EntityListParams) =>\n apiClient.get<PaginatedResponse<T>>(basePath, params),\n\n /**\n * Get a single entity by ID\n * Returns the entity directly (unwrapped from SingleResponse)\n */\n get: async (id: string): Promise<T> => {\n const response = await apiClient.get<SingleResponse<T>>(`${basePath}/${id}`)\n return response.data\n },\n\n /**\n * Create a new entity\n * Returns the created entity directly (unwrapped from SingleResponse)\n */\n create: async (data: CreateInput): Promise<T> => {\n const response = await apiClient.post<SingleResponse<T>>(basePath, data)\n return response.data\n },\n\n /**\n * Update an existing entity\n * Returns the updated entity directly (unwrapped from SingleResponse)\n */\n update: async (id: string, data: UpdateInput): Promise<T> => {\n const response = await apiClient.patch<SingleResponse<T>>(`${basePath}/${id}`, data)\n return response.data\n },\n\n /**\n * Delete an entity\n * Returns void (no content expected from DELETE operations)\n */\n delete: (id: string): Promise<void> =>\n apiClient.delete<void>(`${basePath}/${id}`),\n }\n}\n"],"mappings":"AAOA,SAAS,iBAAiB;AAkCnB,SAAS,gBACd,YACwC;AACxC,QAAM,WAAW,WAAW,UAAU;AAEtC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL,MAAM,CAAC,WACL,UAAU,IAA0B,UAAU,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAMtD,KAAK,OAAO,OAA2B;AACrC,YAAM,WAAW,MAAM,UAAU,IAAuB,GAAG,QAAQ,IAAI,EAAE,EAAE;AAC3E,aAAO,SAAS;AAAA,IAClB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,QAAQ,OAAO,SAAkC;AAC/C,YAAM,WAAW,MAAM,UAAU,KAAwB,UAAU,IAAI;AACvE,aAAO,SAAS;AAAA,IAClB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,QAAQ,OAAO,IAAY,SAAkC;AAC3D,YAAM,WAAW,MAAM,UAAU,MAAyB,GAAG,QAAQ,IAAI,EAAE,IAAI,IAAI;AACnF,aAAO,SAAS;AAAA,IAClB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,QAAQ,CAAC,OACP,UAAU,OAAa,GAAG,QAAQ,IAAI,EAAE,EAAE;AAAA,EAC9C;AACF;","names":[]}
@@ -1,4 +1,4 @@
1
- import { PaginatedResponse, SingleResponse } from '../client.types.js';
1
+ import { PaginatedResponse } from '../client.types.js';
2
2
 
3
3
  /**
4
4
  * Entity API Types
@@ -20,12 +20,15 @@ interface EntityListParams {
20
20
  /**
21
21
  * Generic entity API interface
22
22
  * Matches NextSpark web BaseEntityService pattern
23
+ *
24
+ * Note: get, create, and update return the entity directly (T),
25
+ * not wrapped in SingleResponse<T>. This provides a cleaner API.
23
26
  */
24
27
  interface EntityApi<T, CreateInput, UpdateInput> {
25
28
  list: (params?: EntityListParams) => Promise<PaginatedResponse<T>>;
26
- get: (id: string) => Promise<SingleResponse<T>>;
27
- create: (data: CreateInput) => Promise<SingleResponse<T>>;
28
- update: (id: string, data: UpdateInput) => Promise<SingleResponse<T>>;
29
+ get: (id: string) => Promise<T>;
30
+ create: (data: CreateInput) => Promise<T>;
31
+ update: (id: string, data: UpdateInput) => Promise<T>;
29
32
  delete: (id: string) => Promise<void>;
30
33
  }
31
34
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/mobile",
3
- "version": "0.1.0-beta.1",
3
+ "version": "0.1.0-beta.76",
4
4
  "description": "Mobile app infrastructure for NextSpark - API client, providers, and utilities for Expo apps",
5
5
  "license": "MIT",
6
6
  "author": "NextSpark <hello@nextspark.dev>",