Skip to content

Version History

Current version: 2.0.0

2.0.0

  • Added forwardRequest(). It relays a request to a destination of your choosing from the server and streams the response back as it arrives, with the project's API key attached server side where the browser cannot read it. See Forward Request.
  • A service is now called a project, and the service ID is now the project ID. The single-token form is the primary way to initialize: new Skapi("<Project ID>"). The legacy service ID + owner ID pair is still accepted, and the SDK keeps the older names in its API surface, so service_name, service_description, the service parameter and refetchServiceInfo are unchanged. Documentation examples now use the "<Project ID>" placeholder, angle brackets included.
  • New skapi.project_id class property, also returned by getConnectionInfo(): the public project ID token, composed from the connected project and its owner. Empty string when the project has no user owner.
  • clientSecretRequestHistory() accepts compact, queue_exact and queue_exclude. compact returns label stubs in place of request and response bodies, which can be far larger than the listing that shows them; queue_exact restricts a queue filter to exactly the named queue instead of matching it as a prefix, and queue_exclude drops one queue's rows. Queue filters apply after the range read, so a page can come back short while more matches remain: keep paging by startKey / endOfList, never by a page's length. See Request History and RequestHistory.
  • Fixed: url and method were ignored whenever a queue was given, so two different APIs sharing a queue name reported each other's requests.
  • Fixed: an uncaught QuotaExceededError while saving the session cache. A large paged request history could exceed the session storage quota, which surfaced as an uncaught error on every tab switch.

1.8.3

  • Private files in a record's bin are now cached by the browser for a week. A private file is served under a URL that changes on every read, so browsers could never reuse it and the same file was downloaded again on every read. The first getFile() now downloads it and the rest are served locally, with no network request; take the URL from getFile("endpoint") to get the cached one. The url property on the bin object is unchanged, since that is the string remove_bin and deleteFiles expect back. Files reached through a granted private access key are unchanged, since their URL cannot be minted in a cacheable form.
  • getFile() accepts browserCache and refresh. A URL requested with expires is signed fresh on every call, and since browsers cache by URL, the same unchanged file was downloaded again on every page load. browserCache caches the request that mints the URL instead, so the same URL comes back and the copy already downloaded stays usable, while expires stays as short as you like. refresh bypasses that cached URL, for a file that has changed or a load that failed because the cached URL had expired. See Caching Expiring Files.
  • Fixed: the client refused values the API accepts. Every key-segment length limit was checked against an SDK-only cap that was stricter than the platform's, so legal values were rejected before a request was ever sent: a tag was capped at 64 characters and a table.name / index.name at 128, where the API allows 256 for each. All three now match the API. index.value was already correct at 256.
  • table.name, index.name and each tag are limited to 256 characters, and /, !, *, # and % count as 3 characters each toward that limit. A value that only overflows because of them is now refused with a message saying so, instead of failing as an opaque server error. index.value has no such rule: every character counts as one.
  • Fixed: a table.name, index.name or tag containing a % came back changed. A tag written as 100%25off was returned as 100%off, and a%2Fb as a/b. Any string now reads back exactly as it was written.
  • Fixed: a string index.value containing a % came back changed the same way, so a%2Fb was returned as a/b. Index values now read back exactly as written, and still compare exactly as written for >, <, range, and the >= 'starts with' and <= 'ends with' forms.
  • Fixed: getTables(), getTags() and getIndexes() could not find a table or tag whose name contains /, !, * or #; the lookup returned nothing. They now match. An empty filter paired with a condition still means 'list everything'.
  • Fixed: a file whose name contains a % went missing from record.bin entirely, and one named 50%20off.pdf came back renamed to 50 off.pdf, which no longer matched the stored file. Filenames now come back exactly as uploaded, agreeing with getFile(url, { dataType: 'info' }). For the same reason remove_bin now removes such a file instead of silently doing nothing.
  • Fixed: source.referencing_index_restrictions[].name came back altered when it contained /, !, * or #, unlike index.name for the same string. Reading a record and re-saving it then broke referencing with 'Index value does not match the reference index restriction'.
  • Fixed: a nest query (an index.name ending in a period, which matches the children of a compound index) could not find a child whose name contains /, !, *, # or %. A compound index such as Band.Rock/Pop.year returned nothing from the query meant to find it. index.value, index.range, and order.value on getIndexes() when order.by is index_name, all match now.

1.8.2

  • Fixed: the local unique ID cache introduced in 1.7.1 was not scoped to a service, so one Skapi instance used across several services could resolve a unique ID to a record ID belonging to a different service. The symptom was a post whose reference was a unique ID being rejected with NOT_EXISTS, naming a record ID the caller never supplied. It only showed up when the same unique ID existed in more than one service, for example the same filename uploaded to two projects, and whichever service wrote to the cache last won. The cache is now keyed by service and owner, so a unique ID only ever resolves within the service the call targets.
  • bulkPostRecords() result items now carry the reason a record was refused. The API reports a per-record rejection as an element inside the returned list rather than by throwing, and that element used to arrive as an empty record with the reason stripped, so a caller could not tell a rejection from a save. A refused element still has an empty record_id, which remains the test for whether a record saved, and now also carries error with the API's code and message. See RecordData.

1.8.0

  • getRecords() and deleteRecords(): condition: '<=' on a string index value is now an 'ends with' search. It was a lexicographic 'lesser or equal' comparison before, so any query that relied on the old meaning has to be rewritten. >= is unchanged and still means 'starts with', > and < are still lexicographic, and number / boolean values compare as before. When the index name is a compound name ending in a period, >= and <= match the child name segment from its start and its end respectively. This behavior is served by the API, so it applies to every client version; the SDK type declarations were updated to describe it. See Indexing.
  • clientSecretRequestHistory() items now carry a created timestamp: the time the request was made, in milliseconds, stamped once and never rewritten. updated keeps its meaning as the time of the most recent status change, which for a settled request is when its response arrived. See Fetching Request History.

1.7.7

  • Added stopClientSecretPolling() to stop polling for client-secret requests without cancelling them. The request continues on the server; only the client stops asking. Stop a single request by id, a whole queue by queue, or every live poll by passing no arguments. Returns the number of polls stopped.
  • Added isPollStopped() to tell a stopped poll apart from a real API result.
  • The promise returned by poll() now carries a stop() method that stops that one poll.
  • A stopped poll resolves with { id, status: 'stopped' } instead of rejecting, and its onResponse / onError callbacks are not called. Stopping a request that is still waiting in a queue also removes it from that queue, freeing the slot for the next request.
  • Backend (ships with the API, not the SDK): queue_name is now the plain queue name on every response that carries it. Polling a single request previously returned the internal queue id ("<service>:<queue>|<sequence>") in that field, while history listings returned the plain name.

1.7.1

  • postRecord() and bulkPostRecords() now accept a unique ID in place of record_id when updating a record. A locally known unique ID is resolved to its record ID on the client; otherwise the value is passed through for the server to resolve.

1.7.0

  • Added the refetchServiceInfo class initialization option. When true, cached service info is bypassed and fresh service info is fetched on load.
  • Fixed a bug where large bulk uploads could fail while persisting the local unique-ID map. Writes to session storage are now debounced and guarded, so a full or unavailable session storage no longer interrupts an upload.

1.6.3

  • Added routing for the file text-extraction endpoint, enabling server-side text extraction from uploaded files.

1.6.2

  • getRecords() table parameter now accepts a plain string as shorthand for { name: <table> }.
  • getRecords() reference parameter now accepts an object form { record_id?, unique_id?, user_id? } in addition to a string.
  • getUniqueId() condition now supports 'ne' / '!=' for negated matching, and its parameters are now optional.
  • subscribeNewsletter() email now accepts an array to subscribe multiple addresses at once.
  • New searchable index values: access_group in getUsers(), bounced in newsletter queries, and number_of_records in getTables().
  • getRealtimeUsers() group is now optional and defaults to the realtime group the user is currently joined to.
  • Corrected many type declarations to match runtime behavior, making previously required parameters optional across getTables(), getTags(), getProfile(), getInvitations(), getRealtimeGroups(), inviteUser(), createAccount(), and others.

1.6.1

  • getConnectionInfo() now returns a conf object exposing service flags: freeze_database, prevent_signup, prevent_inquiry, and prevent_anonymous.

1.6.0

  • Added clientSecretRequest() support for secure third-party API calls using saved client secrets.
  • Added automatic polling with poll and manual polling via returned poll() when status is running or pending.
  • Added optional queue support so requests with the same queue name are processed sequentially.
  • Added clientSecretRequestHistory() to list and filter past request results by url, method, status, or queue.
  • Added cancelClientSecretRequest() to cancel pending queued client-secret requests.
  • Added clientSecretRequestQueueCount() to check how many requests are waiting in a named queue.

1.5.8

  • clientSecretRequest() and clientSecretRequestHistory() now reject negative poll values with an INVALID_PARAMETER error.

1.5.7

  • signup() and openidLogin() accept template options for welcome and signup-confirmation emails.
  • Email and phone-number verification methods accept optional template parameters.

1.5.6

  • getConnectionInfo() now supports a refresh parameter to force-refresh the cached connection info.

1.5.5

  • Added ai_agent, service_description, and prevent_anonymous fields to the service connection type.

  • Table names, index names/values, and tag strings are no longer restricted from using delimiter characters.

1.5.4

  • Added queue parameter to clientSecretRequest() and clientSecretRequestHistory(). Requests sharing the same url, method, and queue are processed sequentially in the order they are received. See Client Secret Keys.

1.5.3

  • Fixed access-group condition handling in getTables().

1.5.2

  • Added clientSecretRequestHistory() to retrieve past client-secret request results, with optional polling for items still in pending status. See Client Secret Keys.
  • Added poll parameter to clientSecretRequest() — polling interval in milliseconds for long-running third-party API calls.
  • getTables() now returns dynamic record counts per access group.

1.5.1

  • Improved internal logging.

1.5.0

  • Works with any JavaScript build setup: Node.js, HTML, ESM, CJS, UMD, and TypeScript-based projects.
  • New service ID format: "xxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx" (backward compatible).
  • Refactored and separated internal dependencies: cocochex, qpass.
  • Optimized and reduced build size.

1.2.11

  • HOT FIX: Fixed bug for fetchMore parameter for all requests.

1.2.10

  • Fixed error code on signup().

1.2.9

  • Removed dependency on Queuecumber.
  • Fixed issues with uploading subscription records and feeds.
  • Updated README.md.

1.2.7

  • Fixed types, removed deprecated parameters.

1.2.2

  • Corrected argument types in the class constructor.

1.2.0

  • From 1.2.0 onward, the Skapi class can be initialized with just the service ID, without the owner ID. (Backward compatible)
  • When initializing with a single service ID, use this format: xxxxxxxxxxxx-xxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

1.1.10

  • Fixed a bug where updateProfile() could become unresponsive.

1.1.8

  • Added several utility features. See Utilities

1.1.6

1.1.5

  • Fixed a bug where multiple getRecords() requests sometimes resolve with empty record data.

1.1.4

  • Fixed a bug in listPrivateRecordAccess() parameter handling.

1.1.3

  • Corrected type declarations for the constructor options.
  • Now users can list granted users of private records via listPrivateRecordAccess(). See List Private Access Grants

1.1.2

  • No breaking changes in this release.
  • Skapi now queues requests in batches for efficiency (Default: 30 requests per batch).
  • Skapi now provides more advanced class initialization options, including event listeners for login state, user profile updates, and batch processing. See Advanced Settings.
  • getNewsletters() can now search for bounced emails and display delivery counts per email.

1.0.265

  • Bug fix: Minor fix for admin purposes.

1.0.264

  • Anonymous users can now use skapi.postRecord(). Only limited to public records.
  • Bug fix: skapi.getTags() not resolving proper data.

1.0.262

  • Corrected the casing of the resolved string returned by resendSignupConfirmation() to: "SUCCESS: Signup confirmation e-mail has been sent."

  • During class initialization, if the constructor arguments are set to "service_id" and "owner_id", a browser alert displays: Replace "service_id" and "owner_id" with your actual Service ID and Owner ID.

1.0.260:

  • Service admin user invitations are now supported. Learn more
  • Custom unique ID features have been added to the database. Learn more
  • Database referencing now offers index restriction controls, enabling fine-grained data ownership management. Learn more
  • The database subscription feature is now available. Learn more
  • WebRTC and Web notification are now available, making it easy to build video chat and notification features for your application.
  • Fixed various minor bugs.