@simpleplatform/sdk 1.0.4 → 1.2.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/dist/ai.d.ts +49 -0
- package/dist/ai.js +106 -0
- package/dist/storage.d.ts +26 -0
- package/dist/storage.js +48 -3
- package/dist/types.d.ts +13 -4
- package/dist/worker-override.js +7 -8
- package/package.json +3 -3
package/dist/ai.d.ts
CHANGED
|
@@ -157,6 +157,21 @@ export interface AITranscribeOptions extends Omit<AICommonOptions, 'prompt'> {
|
|
|
157
157
|
*/
|
|
158
158
|
summarize?: boolean;
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Options for searching faces within the Face Engine.
|
|
162
|
+
*/
|
|
163
|
+
export interface AIFaceSearchOptions {
|
|
164
|
+
/**
|
|
165
|
+
* Maximum number of matches to return.
|
|
166
|
+
* Defaults to 5.
|
|
167
|
+
*/
|
|
168
|
+
maxFaces?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Minimum similarity percentage (0-100) required for a match.
|
|
171
|
+
* Defaults to 85.0.
|
|
172
|
+
*/
|
|
173
|
+
similarityThreshold?: number;
|
|
174
|
+
}
|
|
160
175
|
/**
|
|
161
176
|
* The response structure from a successful AI `extract` or `summarize` operation.
|
|
162
177
|
*/
|
|
@@ -236,4 +251,38 @@ export declare function summarize(input: DocumentHandle | object | string, optio
|
|
|
236
251
|
* // Returns: { language: "en", summary: "...", participants: ["Participant 1", "Participant 2"] }
|
|
237
252
|
*/
|
|
238
253
|
export declare function transcribe(input: DocumentHandle, options: AITranscribeOptions, context: Context): Promise<AIExecutionResult>;
|
|
254
|
+
/**
|
|
255
|
+
* Enrolls a face for a subject. The face is associated with the given `subjectId`
|
|
256
|
+
* within the tenant's secure collection.
|
|
257
|
+
*
|
|
258
|
+
* @param subjectId A unique identifier for the subject (e.g., employee ID, user ID).
|
|
259
|
+
* @param image The image containing the face to enroll. Can be a base64 string or a DocumentHandle.
|
|
260
|
+
* @param context The execution context provided by the host.
|
|
261
|
+
* @returns A promise that resolves to an object containing the enrolled `face_id`.
|
|
262
|
+
* @throws Will throw an error if the operation fails or inputs are invalid.
|
|
263
|
+
*/
|
|
264
|
+
export declare function enrollFace(subjectId: string, image: DocumentHandle | string, context: Context): Promise<{
|
|
265
|
+
face_id: string;
|
|
266
|
+
}>;
|
|
267
|
+
/**
|
|
268
|
+
* Searches for faces matching the provided image within the tenant's collection.
|
|
269
|
+
*
|
|
270
|
+
* @param image The image to search for. Can be a base64 string or a DocumentHandle.
|
|
271
|
+
* @param options Configuration for the search operation (e.g., maxFaces, similarityThreshold).
|
|
272
|
+
* @param context The execution context provided by the host.
|
|
273
|
+
* @returns A promise that resolves to a list of matching faces and their confidence scores.
|
|
274
|
+
* @throws Will throw an error if the operation fails or inputs are invalid.
|
|
275
|
+
*/
|
|
276
|
+
export declare function searchFace(image: DocumentHandle | string, options: AIFaceSearchOptions | undefined, context: Context): Promise<any>;
|
|
277
|
+
/**
|
|
278
|
+
* Deletes one or more faces from the tenant's collection by their face IDs.
|
|
279
|
+
*
|
|
280
|
+
* @param faceIds An array of face IDs to delete.
|
|
281
|
+
* @param context The execution context provided by the host.
|
|
282
|
+
* @returns A promise that resolves to an object indicating the IDs of successfully deleted faces.
|
|
283
|
+
* @throws Will throw an error if the operation fails.
|
|
284
|
+
*/
|
|
285
|
+
export declare function deleteFace(faceIds: string[], context: Context): Promise<{
|
|
286
|
+
deleted: string[];
|
|
287
|
+
}>;
|
|
239
288
|
export {};
|
package/dist/ai.js
CHANGED
|
@@ -263,3 +263,109 @@ export async function transcribe(input, options, context) {
|
|
|
263
263
|
schema,
|
|
264
264
|
}, context);
|
|
265
265
|
}
|
|
266
|
+
// ============================================================================
|
|
267
|
+
// Face Recognition API
|
|
268
|
+
// ============================================================================
|
|
269
|
+
let _collectionEnsured = false;
|
|
270
|
+
/**
|
|
271
|
+
* Internal helper to ensure the face collection exists before making face operations.
|
|
272
|
+
* Caches the result per Javascript isolate execution to minimize RPC overhead over
|
|
273
|
+
* sequential calls in the same logic.
|
|
274
|
+
*/
|
|
275
|
+
async function _ensureFaceCollection(context) {
|
|
276
|
+
if (_collectionEnsured)
|
|
277
|
+
return;
|
|
278
|
+
const response = await hostExecute('action:ai/face/ensure-collection', {}, context);
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
throw new Error(response.error?.message || 'Failed to ensure face collection.');
|
|
281
|
+
}
|
|
282
|
+
_collectionEnsured = true;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Enrolls a face for a subject. The face is associated with the given `subjectId`
|
|
286
|
+
* within the tenant's secure collection.
|
|
287
|
+
*
|
|
288
|
+
* @param subjectId A unique identifier for the subject (e.g., employee ID, user ID).
|
|
289
|
+
* @param image The image containing the face to enroll. Can be a base64 string or a DocumentHandle.
|
|
290
|
+
* @param context The execution context provided by the host.
|
|
291
|
+
* @returns A promise that resolves to an object containing the enrolled `face_id`.
|
|
292
|
+
* @throws Will throw an error if the operation fails or inputs are invalid.
|
|
293
|
+
*/
|
|
294
|
+
export async function enrollFace(subjectId, image, context) {
|
|
295
|
+
if (!subjectId) {
|
|
296
|
+
throw new Error('The `subjectId` parameter is required for `enrollFace`.');
|
|
297
|
+
}
|
|
298
|
+
if (!image) {
|
|
299
|
+
throw new Error('The `image` parameter is required for `enrollFace`.');
|
|
300
|
+
}
|
|
301
|
+
// Ensure the tenant's collection is ready before enrolling
|
|
302
|
+
await _ensureFaceCollection(context);
|
|
303
|
+
// Upload pending documents if given handles
|
|
304
|
+
const processedImage = await _uploadPendingFiles(image, context);
|
|
305
|
+
const payload = {
|
|
306
|
+
image: processedImage,
|
|
307
|
+
subject_id: subjectId,
|
|
308
|
+
};
|
|
309
|
+
const response = await hostExecute('action:ai/face/enroll', payload, context);
|
|
310
|
+
if (!response.ok) {
|
|
311
|
+
throw new Error(response.error?.message || 'Face enrollment failed.');
|
|
312
|
+
}
|
|
313
|
+
return response.data;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Searches for faces matching the provided image within the tenant's collection.
|
|
317
|
+
*
|
|
318
|
+
* @param image The image to search for. Can be a base64 string or a DocumentHandle.
|
|
319
|
+
* @param options Configuration for the search operation (e.g., maxFaces, similarityThreshold).
|
|
320
|
+
* @param context The execution context provided by the host.
|
|
321
|
+
* @returns A promise that resolves to a list of matching faces and their confidence scores.
|
|
322
|
+
* @throws Will throw an error if the operation fails or inputs are invalid.
|
|
323
|
+
*/
|
|
324
|
+
export async function searchFace(image, options = {}, context) {
|
|
325
|
+
if (!image) {
|
|
326
|
+
throw new Error('The `image` parameter is required for `searchFace`.');
|
|
327
|
+
}
|
|
328
|
+
// Ensure collection exists before searching
|
|
329
|
+
await _ensureFaceCollection(context);
|
|
330
|
+
const processedImage = await _uploadPendingFiles(image, context);
|
|
331
|
+
// Map JS property names to Elixir convention if needed, though they are passed as options
|
|
332
|
+
// and parsed correctly in simple_logic if expected.
|
|
333
|
+
// The simple_ai FaceEngine expects snake_case for options like max_faces or similarity_threshold.
|
|
334
|
+
const mappedOptions = {};
|
|
335
|
+
if (options.maxFaces !== undefined)
|
|
336
|
+
mappedOptions.max_faces = options.maxFaces;
|
|
337
|
+
if (options.similarityThreshold !== undefined)
|
|
338
|
+
mappedOptions.similarity_threshold = options.similarityThreshold;
|
|
339
|
+
const payload = {
|
|
340
|
+
image: processedImage,
|
|
341
|
+
options: mappedOptions,
|
|
342
|
+
};
|
|
343
|
+
const response = await hostExecute('action:ai/face/search', payload, context);
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
throw new Error(response.error?.message || 'Face search failed.');
|
|
346
|
+
}
|
|
347
|
+
return response.data;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Deletes one or more faces from the tenant's collection by their face IDs.
|
|
351
|
+
*
|
|
352
|
+
* @param faceIds An array of face IDs to delete.
|
|
353
|
+
* @param context The execution context provided by the host.
|
|
354
|
+
* @returns A promise that resolves to an object indicating the IDs of successfully deleted faces.
|
|
355
|
+
* @throws Will throw an error if the operation fails.
|
|
356
|
+
*/
|
|
357
|
+
export async function deleteFace(faceIds, context) {
|
|
358
|
+
if (!faceIds || !Array.isArray(faceIds) || faceIds.length === 0) {
|
|
359
|
+
throw new Error('The `faceIds` parameter must be a non-empty array for `deleteFace`.');
|
|
360
|
+
}
|
|
361
|
+
await _ensureFaceCollection(context);
|
|
362
|
+
const payload = {
|
|
363
|
+
face_ids: faceIds,
|
|
364
|
+
};
|
|
365
|
+
const response = await hostExecute('action:ai/face/delete', payload, context);
|
|
366
|
+
if (!response.ok) {
|
|
367
|
+
throw new Error(response.error?.message || 'Face deletion failed.');
|
|
368
|
+
}
|
|
369
|
+
// Ensure consistent return format
|
|
370
|
+
return { deleted: Array.isArray(response.data) ? response.data : response.data?.deleted || [] };
|
|
371
|
+
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
import type { Context, DocumentHandle, ExternalFileSource, StorageTarget } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Uploads an in-memory binary buffer as a document to the platform's storage system.
|
|
4
|
+
*
|
|
5
|
+
* Accepts any binary content (images, PDFs, etc.) as an `ArrayBuffer` or `Uint8Array`.
|
|
6
|
+
* The bytes are base64-encoded once here at the JSON boundary, decoded on the backend,
|
|
7
|
+
* and then stored via the same pipeline as `uploadExternal`.
|
|
8
|
+
*
|
|
9
|
+
* @param buffer The binary content to upload.
|
|
10
|
+
* @param filename The filename to assign to the stored document.
|
|
11
|
+
* @param mimeType The MIME type of the content (e.g. `'application/pdf'`, `'image/png'`).
|
|
12
|
+
* @param target The target location where the file should be stored.
|
|
13
|
+
* @param context The execution context for the request.
|
|
14
|
+
* @returns A promise that resolves with a DocumentHandle containing file metadata.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const handle = await uploadBuffer(
|
|
19
|
+
* pdfBytes,
|
|
20
|
+
* 'report.pdf',
|
|
21
|
+
* 'application/pdf',
|
|
22
|
+
* { app_id: 'dev.simple.system', table_name: 'documents', field_name: 'attachment' },
|
|
23
|
+
* context
|
|
24
|
+
* )
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function uploadBuffer(buffer: ArrayBuffer | Uint8Array, filename: string, mimeType: string, target: StorageTarget, context: Context): Promise<DocumentHandle>;
|
|
2
28
|
/**
|
|
3
29
|
* Uploads a file from an external URL to the platform's storage system.
|
|
4
30
|
*
|
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,49 @@
|
|
|
1
1
|
import { execute as hostExecute } from './host';
|
|
2
|
+
/**
|
|
3
|
+
* Uploads an in-memory binary buffer as a document to the platform's storage system.
|
|
4
|
+
*
|
|
5
|
+
* Accepts any binary content (images, PDFs, etc.) as an `ArrayBuffer` or `Uint8Array`.
|
|
6
|
+
* The bytes are base64-encoded once here at the JSON boundary, decoded on the backend,
|
|
7
|
+
* and then stored via the same pipeline as `uploadExternal`.
|
|
8
|
+
*
|
|
9
|
+
* @param buffer The binary content to upload.
|
|
10
|
+
* @param filename The filename to assign to the stored document.
|
|
11
|
+
* @param mimeType The MIME type of the content (e.g. `'application/pdf'`, `'image/png'`).
|
|
12
|
+
* @param target The target location where the file should be stored.
|
|
13
|
+
* @param context The execution context for the request.
|
|
14
|
+
* @returns A promise that resolves with a DocumentHandle containing file metadata.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const handle = await uploadBuffer(
|
|
19
|
+
* pdfBytes,
|
|
20
|
+
* 'report.pdf',
|
|
21
|
+
* 'application/pdf',
|
|
22
|
+
* { app_id: 'dev.simple.system', table_name: 'documents', field_name: 'attachment' },
|
|
23
|
+
* context
|
|
24
|
+
* )
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export async function uploadBuffer(buffer, filename, mimeType, target, context) {
|
|
28
|
+
if (!filename || filename.trim() === '')
|
|
29
|
+
throw new Error('filename is required');
|
|
30
|
+
if (!mimeType || mimeType.trim() === '')
|
|
31
|
+
throw new Error('mimeType is required');
|
|
32
|
+
if (!target.app_id || target.app_id.trim() === '')
|
|
33
|
+
throw new Error('Target app_id is required and cannot be empty');
|
|
34
|
+
if (!target.table_name || target.table_name.trim() === '')
|
|
35
|
+
throw new Error('Target table_name is required and cannot be empty');
|
|
36
|
+
if (!target.field_name || target.field_name.trim() === '')
|
|
37
|
+
throw new Error('Target field_name is required and cannot be empty');
|
|
38
|
+
const bytes = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;
|
|
39
|
+
// Base64-encode at the JSON boundary (JSON.stringify cannot carry raw binary)
|
|
40
|
+
const base64 = btoa(String.fromCharCode(...bytes));
|
|
41
|
+
const source = { bytes: base64, filename, mime_type: mimeType };
|
|
42
|
+
const response = await hostExecute('action:storage/upload-external', { source, target }, context);
|
|
43
|
+
if (!response.ok)
|
|
44
|
+
throw new Error(response.error?.message ?? 'Buffer upload failed');
|
|
45
|
+
return response.data;
|
|
46
|
+
}
|
|
2
47
|
/**
|
|
3
48
|
* Uploads a file from an external URL to the platform's storage system.
|
|
4
49
|
*
|
|
@@ -32,9 +77,9 @@ import { execute as hostExecute } from './host';
|
|
|
32
77
|
* ```
|
|
33
78
|
*/
|
|
34
79
|
export async function uploadExternal(source, target, context) {
|
|
35
|
-
// Validate source
|
|
36
|
-
if (!source.url || source.url.trim() === '') {
|
|
37
|
-
throw new Error('
|
|
80
|
+
// Validate source: must have either url or bytes
|
|
81
|
+
if ((!source.url || source.url.trim() === '') && !source.bytes) {
|
|
82
|
+
throw new Error('Either source URL or bytes must be provided');
|
|
38
83
|
}
|
|
39
84
|
// Validate target
|
|
40
85
|
if (!target.app_id || target.app_id.trim() === '') {
|
package/dist/types.d.ts
CHANGED
|
@@ -20,9 +20,9 @@ export interface DocumentHandle {
|
|
|
20
20
|
/** The storage path where the file is stored. */
|
|
21
21
|
storage_path: string;
|
|
22
22
|
}
|
|
23
|
-
/** Represents the source configuration for
|
|
23
|
+
/** Represents the source configuration for an external file upload (URL or in-memory bytes). */
|
|
24
24
|
export interface ExternalFileSource {
|
|
25
|
-
/** Optional authentication configuration for accessing the external file. */
|
|
25
|
+
/** Optional authentication configuration for accessing the external file (URL path only). */
|
|
26
26
|
auth?: {
|
|
27
27
|
/** Bearer token for bearer authentication. */
|
|
28
28
|
bearer_token?: string;
|
|
@@ -33,8 +33,17 @@ export interface ExternalFileSource {
|
|
|
33
33
|
/** Username for basic authentication. */
|
|
34
34
|
username?: string;
|
|
35
35
|
};
|
|
36
|
-
/**
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Base64-encoded binary content for in-memory uploads.
|
|
38
|
+
* Use this with `filename` and `mime_type` instead of `url`.
|
|
39
|
+
*/
|
|
40
|
+
bytes?: string;
|
|
41
|
+
/** Original filename — required when using `bytes`. */
|
|
42
|
+
filename?: string;
|
|
43
|
+
/** MIME type of the file — required when using `bytes`. */
|
|
44
|
+
mime_type?: string;
|
|
45
|
+
/** The URL of the external file to download. Mutually exclusive with `bytes`. */
|
|
46
|
+
url?: string;
|
|
38
47
|
}
|
|
39
48
|
/** Contains metadata about the specific logic execution. */
|
|
40
49
|
export interface Logic {
|
package/dist/worker-override.js
CHANGED
|
@@ -11,22 +11,21 @@ const pendingHostRequests = new Map()
|
|
|
11
11
|
|
|
12
12
|
// eslint-disable-next-line no-restricted-globals
|
|
13
13
|
self.addEventListener('message', (event) => {
|
|
14
|
-
const message = event
|
|
15
|
-
if (
|
|
16
|
-
typeof message !== 'object'
|
|
17
|
-
|| message === null
|
|
18
|
-
|| message.type !== 'host_response'
|
|
19
|
-
) {
|
|
14
|
+
const message = event.data
|
|
15
|
+
if (message.type !== 'host_response')
|
|
20
16
|
return
|
|
21
|
-
}
|
|
22
17
|
|
|
23
18
|
const pending = pendingHostRequests.get(message.requestId)
|
|
24
19
|
if (!pending)
|
|
25
20
|
return
|
|
26
21
|
|
|
22
|
+
const errorMsg = typeof message.response.error === 'object' && message.response.error?.message
|
|
23
|
+
? message.response.error.message
|
|
24
|
+
: message.response.error ?? 'Unknown host error'
|
|
25
|
+
|
|
27
26
|
message.response.ok
|
|
28
27
|
? pending.resolve(message.response)
|
|
29
|
-
: pending.reject(new Error(
|
|
28
|
+
: pending.reject(new Error(errorMsg))
|
|
30
29
|
|
|
31
30
|
pendingHostRequests.delete(message.requestId)
|
|
32
31
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simpleplatform/sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Simple Platform Typescript SDK",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://docs.simple.dev",
|
|
@@ -61,10 +61,10 @@
|
|
|
61
61
|
"dist"
|
|
62
62
|
],
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"esbuild": "0.27.
|
|
64
|
+
"esbuild": "0.27.4"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@types/node": "25.
|
|
67
|
+
"@types/node": "25.5.0",
|
|
68
68
|
"typescript": "5.9.3"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|