@makemind/sdk
v0.1.0
Published
MAKEMIND Platform SDK for Web Applications
Maintainers
Readme
@makemind/sdk
MAKEMIND Platform SDK for Web Applications (React, Vue, Angular, etc.)
Installation
npm install @makemind/sdkThe SDK talks to the MAKEMIND API gateway over HTTPS. Installing it pulls in nothing else: you only need an API key and your application ID.
firebase is an optional peer. Two features load it on demand and only
when you use them — web push (messaging.registerDevice,
messaging.onPushMessage) and App Check tokens. Everything else, including
every gateway call, works with firebase absent.
Quick Start
import { initializeMAKEMIND, getMAKEMIND } from '@makemind/sdk';
// Initialize MAKEMIND SDK
initializeMAKEMIND({
apiKey: 'your-api-key',
applicationId: 'plm', // Your application ID
environment: 'development',
// Optional: override the gateway base URL (defaults to https://api.makemind.app).
// Point this at a locally running gateway during development.
baseUrl: 'http://127.0.0.1:5001/<project-id>/us-central1/apiGateway',
});
// Use the SDK
const makemind = getMAKEMIND();initializeMAKEMIND accepts { apiKey, applicationId, environment?, baseUrl?, apiVersion?, getAppCheckToken? }.
All service calls are issued against ${baseUrl}/api/${apiVersion} (apiVersion
defaults to v1).
App Check (first-party apps only)
Pass getAppCheckToken — an async provider returning a Firebase App Check
token — to have the SDK attach it as X-Firebase-AppCheck on every gateway
call. This lets browser/mobile apps pass App Check enforcement on the pre-login
endpoints (signin/signup/password-reset/oauth). Backward-compatible: omit it for
M2M / API-key integrations (exempt from App Check server-side), and a provider
returning null simply omits the header.
import { getToken } from 'firebase/app-check';
initializeMAKEMIND({
apiKey, applicationId,
getAppCheckToken: async () => (await getToken(appCheck, false)).token,
});Authentication
const makemind = getMAKEMIND();
// Sign in with email + password
const user = await makemind.auth.signInWithEmail(email, password);
// Sign up a new user
const newUser = await makemind.auth.signUp(email, password, {
displayName: 'Jane Doe',
});
// Listen to auth state changes
const unsubscribe = makemind.auth.onAuthStateChanged((user) => {
if (user) {
console.log('User signed in:', user.uid);
console.log('Tenant:', user.tenantId);
console.log('Roles:', user.roles);
}
});
// Sign out
await makemind.auth.signOut();
// Get user memberships (tenants user belongs to)
const memberships = await makemind.auth.getUserMemberships();
// Switch tenant
await makemind.auth.switchTenant('new-tenant-id');Data Operations
const makemind = getMAKEMIND();
// Query with tenant isolation
const { data: products } = await makemind.data.query({
collection: 'plm_products',
where: [
{ field: 'tenant_id', op: '==', value: makemind.tenantId },
{ field: 'status', op: '==', value: 'active' },
],
orderBy: [{ field: 'created_at', direction: 'desc' }],
limit: 20,
});
// Get single document
const product = await makemind.data.get({
collection: 'plm_products',
documentId: 'product-id',
});
// Create document (tenant_id auto-added)
const result = await makemind.data.create({
collection: 'plm_products',
data: {
product_code: 'PRD-001',
product_name: 'Sample Product',
status: 'development',
},
});
// Update document
await makemind.data.update({
collection: 'plm_products',
documentId: 'product-id',
data: { status: 'active' },
});
// Real-time subscription
const unsubscribe = makemind.data.onCollectionSnapshot(
{
collection: 'plm_products',
where: [{ field: 'tenant_id', op: '==', value: makemind.tenantId }],
},
(products) => {
console.log('Products updated:', products);
}
);
// Cleanup
unsubscribe();Logic / Workflows
const makemind = getMAKEMIND();
// ECO workflow transition
await makemind.logic.ecoTransition('eco-id', 'submit');
await makemind.logic.ecoTransition('eco-id', 'approve', {
comments: 'Approved for implementation',
});
// NCR workflow
await makemind.logic.ncrTransition('issue-id', 'assignContainment', {
assignedTo: 'user-id',
containmentAction: 'Quarantine affected parts',
});
// Marketplace bid
await makemind.logic.bidTransition('request-id', 'bid-id', 'submit');
// Gate approval
await makemind.logic.gateApproval('product-id', 'production', 'approve');
// Generic flow execution
const result = await makemind.logic.executeFlow('flow-id', {
input: 'data',
});Tenant Management
const makemind = getMAKEMIND();
// Get current tenant
const tenant = await makemind.tenant.getCurrent();
// Update tenant settings
await makemind.tenant.updateTenant({
settings: { industryType: 'electronics' },
});
// List members
const members = await makemind.tenant.listMembers();
// Invite member
await makemind.tenant.inviteMember({
email: '[email protected]',
role: 'manager',
});
// Workspaces
const workspaces = await makemind.tenant.listWorkspaces();
await makemind.tenant.createWorkspace({
name: 'Development Team',
description: 'R&D workspace',
});Messaging / Notifications
const makemind = getMAKEMIND();
// Send notification
await makemind.messaging.send({
template: 'ecoReviewRequest',
recipients: ['user-1', 'user-2'],
data: {
ecoNumber: 'ECO-2024-001',
title: 'Design Change Request',
},
channels: ['push', 'email'],
});
// Listen to notifications
const unsubscribe = makemind.messaging.onNotifications(
(notifications) => {
console.log('Notifications:', notifications);
},
{ unreadOnly: true }
);
// Mark as read
await makemind.messaging.markAsRead('notification-id');Settlement / Billing
const makemind = getMAKEMIND();
// Record usage event
await makemind.settlement.recordProductCreation('product-id');
await makemind.settlement.recordDocumentUpload('doc-id', 2.5); // 2.5 MB
// Get usage stats
const stats = await makemind.settlement.getUsageStats('currentMonth');
// Get billing summary
const billing = await makemind.settlement.getBillingSummary();
// Check quotas
const quotas = await makemind.settlement.getQuotaStatus();
// List invoices
const invoices = await makemind.settlement.listInvoices({ status: 'pending' });Storage
const makemind = getMAKEMIND();
// Upload a file
const uploaded = await makemind.storage.upload({
path: 'products/product-id/documents/spec.pdf',
file: fileFromInput, // File | Blob
metadata: { documentType: 'spec' },
onProgress: (progress) => console.log(`${progress.toFixed(0)}%`),
});
// Get a download URL / download directly
const url = await makemind.storage.getDownloadUrl('products/product-id/documents/spec.pdf');
const blob = await makemind.storage.download('products/product-id/documents/spec.pdf');
// List, copy, move, delete
const { files } = await makemind.storage.listFiles({ prefix: 'products/product-id/documents/' });
await makemind.storage.copy('a.pdf', 'b.pdf');
await makemind.storage.move('a.pdf', 'archive/a.pdf');
await makemind.storage.delete('a.pdf');
// PLM-specific helpers
await makemind.storage.uploadProductDocument('product-id', file, { documentType: 'drawing' });
await makemind.storage.uploadEcoAttachment('eco-id', file);
await makemind.storage.uploadQualityAttachment('issue-id', file);
const productDocs = await makemind.storage.getProductDocuments('product-id');
// Bucket management
const buckets = await makemind.storage.listBuckets();
await makemind.storage.createBucket({ name: 'reports', publicAccess: false });
const stats = await makemind.storage.getUsageStats();AI
const makemind = getMAKEMIND();
// Chat completion
const { message, usage } = await makemind.ai.chat([
{ role: 'user', content: 'Summarize this ECO for a release note.' },
]);
// Streaming (polling-based; delivers content deltas as they arrive)
await makemind.ai.chatStream(
[{ role: 'user', content: 'Draft a quality report.' }],
(chunk) => process.stdout.write(chunk),
{ onDone: (response) => console.log('done', response.usage) }
);
// Or consume as an async generator
for await (const delta of makemind.ai.streamChat([{ role: 'user', content: 'Hi' }])) {
console.log(delta);
}
// Embeddings
const { embeddings } = await makemind.ai.createEmbedding(['spec text', 'another doc']);
// Vector search over a tenant knowledge collection
const hits = await makemind.ai.vectorSearch('specs', 'torque tolerance', { limit: 5 });
// Vision
await makemind.ai.analyzeImage('https://example.com/part.png', 'Describe this part.');
await makemind.ai.analyzeImageBase64(base64Data, 'image/png', 'Describe this part.');
// Tool calling
const { toolCalls } = await makemind.ai.chatWithTools(
[{ role: 'user', content: 'Look up product PRD-001.' }],
[{ name: 'getProduct', description: 'Fetch a product by code', parameters: { type: 'object' } }]
);
// Convenience helpers
const { text } = await makemind.ai.generate('Write a one-line changelog entry.');
const { summary } = await makemind.ai.summarize(longText, { style: 'bullet', maxLength: 100 });
const { translation } = await makemind.ai.translate('Hello world', 'ko');Search
const makemind = getMAKEMIND();
// Simple query
const results = await makemind.search.query({ q: 'bracket', collections: ['plm_products'], perPage: 20 });
// Advanced query with facets/filters/highlighting
const advanced = await makemind.search.advanced({
query: 'bracket',
collection: 'plm_products',
facets: ['status', 'category'],
filters: { status: 'active' },
highlightFields: ['product_name'],
});
// Autocomplete suggestions
const suggestions = await makemind.search.suggestions({ prefix: 'brac', collection: 'plm_products' });
// Analytics and reindexing
const analytics = await makemind.search.getAnalytics({ startDate: '2026-01-01' });
const { jobId } = await makemind.search.bulkReindex({ collection: 'plm_products' });
const status = await makemind.search.getBulkReindexStatus({ jobId });Apps (App Builder)
const makemind = getMAKEMIND();
// Create and manage apps
const { appId } = await makemind.apps.createApp({ name: 'field-service', displayName: 'Field Service' });
const app = await makemind.apps.getApp(appId);
const { apps } = await makemind.apps.listApps({ status: 'draft' });
await makemind.apps.updateApp(appId, { settings: { theme: { mode: 'dark' } } });
// Pages
const { pageId } = await makemind.apps.createPage(appId, { name: 'Home', path: '/', isHomePage: true });
await makemind.apps.updatePage(appId, pageId, { title: 'Home' });
const pages = await makemind.apps.listPages(appId);
// Publishing & versioning
await makemind.apps.publish(appId, 'Initial release');
const versions = await makemind.apps.getVersions(appId);
await makemind.apps.rollback(appId, versions[0].version);
// Domains
await makemind.apps.addSubdomain(appId, 'field-service');
const { verificationToken, dnsRecords } = await makemind.apps.addCustomDomain(appId, 'app.example.com');
// AI-assisted UI generation
const { components } = await makemind.apps.generateUI('A form to log a quality issue');
// Live-edit collaboration
const { sessionToken, wsEndpoint } = await makemind.apps.startSession(appId, pageId);Marketplace
const makemind = getMAKEMIND();
// Discovery
const results = await makemind.marketplace.search({ query: 'inventory', category: 'operations' });
const listing = await makemind.marketplace.getDetail('listing-id');
const featured = await makemind.marketplace.getFeatured();
// Installation
const { bindingId } = await makemind.marketplace.install('listing-id');
const installed = await makemind.marketplace.listInstalled();
await makemind.marketplace.uninstall('listing-id');
// App runtime (proxy calls through the installed binding)
const config = await makemind.marketplace.getConfig(bindingId);
await makemind.marketplace.proxy(bindingId, { method: 'GET', path: 'items' });
// Reviews
await makemind.marketplace.createReview({ listingId: 'listing-id', rating: 5, body: 'Great app' });
const reviews = await makemind.marketplace.listReviews('listing-id');
// Publishing (for publisher tenants)
await makemind.marketplace.createPublisherProfile({
displayName: 'Acme Apps',
description: 'Field service tools',
logoUrl: 'https://example.com/logo.png',
supportEmail: '[email protected]',
});
const newListing = await makemind.marketplace.createListing({ name: 'Inventory Sync' });
await makemind.marketplace.submitForReview((newListing as { listingId: string }).listingId);Platform Operations (Generic Dispatch)
Every typed service method (data.*, tenant.*, messaging.*, ...) is a thin
wrapper around the gateway's RPC dispatch route. When a backend operation does
not yet have a typed service method, call it directly with makemind.call():
const makemind = getMAKEMIND();
// call<T>(operation, input) -> POST /api/v<version>/call/:operation
// The `{ data }` response envelope is already unwrapped.
const result = await makemind.call('updateMyProfile', { displayName: 'Jane Doe' });call(operation, input) invokes a platform Callable operation through the
gateway RPC dispatch route. The operation key is the deployed Callable name:
namespaced groups use <prefix>-<name> (e.g. settlement-getMRR,
marketplace-listPublisherListings); flat exports use the bare name (e.g.
createTenant, updateMyProfile). Each operation enforces its own
authorization server-side (platform roles / tenant scopes), so calling an
operation you are not authorized for still fails with PERMISSION_DENIED —
call() does not bypass access control.
This is distinct from logic.call(functionName, input), which executes a
tenant-defined logic function (POST /logic/call), not a platform Callable.
Some illustrative operations reachable only through call() (no dedicated
typed method yet):
await makemind.call('platformGetAuditLogs', { limit: 50 });
await makemind.call('updateMyProfile', { displayName: 'Jane Doe' });
await makemind.call('endusers-listEndUsers', { limit: 20 });
await makemind.call('knowledge-knowledgeCreateUploadUrl', { fileName: 'spec.pdf' });
await makemind.call('getBillingContact', {});
await makemind.call('updateBillingContact', { email: '[email protected]' });
await makemind.call('getMyLoginHistory', { limit: 10 });
await makemind.call('createBrandingLogoUploadUrl', { fileName: 'logo.png' });
await makemind.call('marketplace-listPublisherListings', {});React Integration Example
// src/lib/makemind.ts
import { initializeMAKEMIND } from '@makemind/sdk';
export const makemind = initializeMAKEMIND({
apiKey: import.meta.env.VITE_MAKEMIND_API_KEY,
applicationId: 'plm',
environment: import.meta.env.DEV ? 'development' : 'production',
baseUrl: import.meta.env.VITE_MAKEMIND_BASE_URL, // optional gateway override
});
// src/hooks/useProducts.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { getMAKEMIND } from '@makemind/sdk';
export function useProducts() {
const makemind = getMAKEMIND();
return useQuery({
queryKey: ['plm_products', makemind.tenantId],
queryFn: async () => {
const result = await makemind.data.query({
collection: 'plm_products',
where: [
{ field: 'tenant_id', op: '==', value: makemind.tenantId! },
],
orderBy: [{ field: 'updated_at', direction: 'desc' }],
});
return result.data;
},
enabled: !!makemind.tenantId,
});
}
export function useCreateProduct() {
const queryClient = useQueryClient();
const makemind = getMAKEMIND();
return useMutation({
mutationFn: async (data: CreateProductInput) => {
const result = await makemind.data.create({
collection: 'plm_products',
data,
});
// Record usage
await makemind.settlement.recordProductCreation(result.id);
return result;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['plm_products'] });
},
});
}Error Handling
import { MAKEMINDError, ErrorCodes } from '@makemind/sdk';
try {
await makemind.data.create({ ... });
} catch (error) {
if (error instanceof MAKEMINDError) {
switch (error.code) {
case ErrorCodes.PERMISSION_DENIED:
console.error('Access denied');
break;
case ErrorCodes.QUOTA_EXCEEDED:
console.error('Quota exceeded');
break;
default:
console.error('Error:', error.message);
}
}
}License
MIT
