Namespaces allow you to filter events so your listeners only respond to specific events within defined scopes.

Basic Usage

// Global listener - responds to all events
listener.on("space:created", event => { ... });

// Namespaced listener - only responds to events in the 'green' space
listener.namespace(['space:green'], (green) => {
  green.on("space:created", event => { ... });
});

Namespace Patterns

Event Type Prefixes

  • space: - Space-level events (e.g., space:configure, space:created, space:updated)
  • workbook: - Workbook-level events (e.g., workbook:created, workbook:submitAction)
  • sheet: - Sheet-level events (e.g., sheet:created, sheet:updated, sheet:deleted)
  • *: - Wildcard pattern to match any event type

Custom Suffixes

Create custom namespaces using the pattern eventType:customSuffix:

// Listen to ALL event types in the 'red' namespace
listener.namespace(['*:red'], (red) => {
  red.filter({ job: 'space:configure' }, (configure) => {
    // Handle space configuration for red namespace
  })
})

// Listen to events in the 'green' space
listener.namespace(['space:green'], (green) => {
  green.filter({ job: 'space:configure' }, (configure) => {
    // Handle space configuration for green space
  })
})

Setting Namespaces

In Spaces

When creating a space via the API, you can assign a namespace:

const space = await api.spaces.create({
  name: "My Space",
  namespace: "my-namespace",
  workbook: {
    // workbook config
  }
});

In Workbooks and Sheets

Workbooks and spaces use namespace, while sheets use slug as their identifier:

const workbook = new Workbook({
  name: 'My Workbook',
  namespace: 'team1',  // Workbook namespace - affects all events from this workbook
  sheets: [
    {
      name: "Contacts",
      slug: "contacts",  // Sheet slug (not namespace) - unique identifier for this sheet
      fields: [
        // your fields here
      ]
    }
  ]
})

Common Naming Patterns

  • :red, :green - Color-based organization
  • :team1, :team2 - Team-based organization
  • :feature1, :feature2 - Feature-based organization
  • :xdk-test, :my-namespace - Project-based organization

Complete Example

Here’s a complete example that sets up a namespaced listener for space configuration:

import api from "@flatfile/api";

export default function flatfileEventListener(listener) {
  listener.namespace(["space:red"], (red) => {
    red.on(
      "job:ready",
      { job: "space:configure" },
      async ({ context: { spaceId, jobId } }) => {
        try {
          await api.jobs.ack(jobId, {
            info: "Configuring red space...",
            progress: 10,
          });

          await api.documents.create(spaceId, {
            title: "Welcome to Red Space",
            body: "# Welcome to your Red Space\n---\n",
          });

          await api.spaces.update(spaceId, {
            metadata: {
              theme: {
                root: { primaryColor: "red" },
                sidebar: {
                  backgroundColor: "red",
                  textColor: "white",
                },
              },
            },
          });

          await api.jobs.complete(jobId, {
            outcome: { message: "Space configured successfully." },
          });
        } catch (error) {
          await api.jobs.fail(jobId, {
            outcome: { message: "Configuration failed." },
          });
        }
      }
    );
  });
}